Vector Fields#
Given two differentiable manifolds \(U\) and \(M\) over the same topological field \(K\) and a differentiable map
we define a vector field along \(U\) with values on \(M\) to be a differentiable map
(\(TM\) being the tangent bundle of \(M\)) such that
The standard case of vector fields on a differentiable manifold corresponds to \(U = M\) and \(\Phi = \mathrm{Id}_M\). Other common cases are \(\Phi\) being an immersion and \(\Phi\) being a curve in \(M\) (\(U\) is then an open interval of \(\RR\)).
Vector fields are implemented via two classes: VectorFieldParal
and
VectorField
, depending respectively whether the manifold \(M\)
is parallelizable or not, i.e. whether the bundle \(TM\) is trivial or not.
AUTHORS:
Eric Gourgoulhon, Michal Bejger (2013-2015) : initial version
Marco Mancini (2015): parallelization of vector field plots
Travis Scrimshaw (2016): review tweaks
Eric Gourgoulhon (2017): vector fields inherit from multivector fields
Eric Gourgoulhon (2018): dot and cross products, operators norm and curl
REFERENCES:
- class sage.manifolds.differentiable.vectorfield.VectorField(vector_field_module, name=None, latex_name=None)#
Bases:
sage.manifolds.differentiable.multivectorfield.MultivectorField
Vector field along a differentiable manifold.
An instance of this class is a vector field along a differentiable manifold \(U\) with values on a differentiable manifold \(M\), via a differentiable map \(U \rightarrow M\). More precisely, given a differentiable map
\[\Phi:\ U \longrightarrow M,\]a vector field along \(U\) with values on \(M\) is a differentiable map
\[v:\ U \longrightarrow TM\](\(TM\) being the tangent bundle of \(M\)) such that
\[\forall p \in U,\ v(p) \in T_{\Phi(p)}M.\]The standard case of vector fields on a differentiable manifold corresponds to \(U = M\) and \(\Phi = \mathrm{Id}_M\). Other common cases are \(\Phi\) being an immersion and \(\Phi\) being a curve in \(M\) (\(U\) is then an open interval of \(\RR\)).
Note
If \(M\) is parallelizable, then
VectorFieldParal
must be used instead.INPUT:
vector_field_module
– module \(\mathfrak{X}(U,\Phi)\) of vector fields along \(U\) with values on \(M\supset\Phi(U)\)name
– (default:None
) name given to the vector fieldlatex_name
– (default:None
) LaTeX symbol to denote the vector field; if none is provided, the LaTeX symbol is set toname
EXAMPLES:
A vector field on a non-parallelizable 2-dimensional manifold:
sage: M = Manifold(2, 'M') sage: U = M.open_subset('U') ; V = M.open_subset('V') sage: M.declare_union(U,V) # M is the union of U and V sage: c_xy.<x,y> = U.chart() ; c_tu.<t,u> = V.chart() sage: transf = c_xy.transition_map(c_tu, (x+y, x-y), intersection_name='W', ....: restrictions1= x>0, restrictions2= t+u>0) sage: inv = transf.inverse() sage: W = U.intersection(V) sage: eU = c_xy.frame() ; eV = c_tu.frame() sage: c_tuW = c_tu.restrict(W) ; eVW = c_tuW.frame() sage: v = M.vector_field(name='v') ; v Vector field v on the 2-dimensional differentiable manifold M sage: v.parent() Module X(M) of vector fields on the 2-dimensional differentiable manifold M
The vector field is first defined on the domain \(U\) by means of its components with respect to the frame
eU
:sage: v[eU,:] = [-y, 1+x]
The components with respect to the frame
eV
are then deduced by continuation of the components with respect to the frameeVW
on the domain \(W = U \cap V\), expressed in terms on the coordinates covering \(V\):sage: v[eV,0] = v[eVW,0,c_tuW].expr() sage: v[eV,1] = v[eVW,1,c_tuW].expr()
At this stage, the vector field is fully defined on the whole manifold:
sage: v.display(eU) v = -y ∂/∂x + (x + 1) ∂/∂y sage: v.display(eV) v = (u + 1) ∂/∂t + (-t - 1) ∂/∂u
The vector field acting on scalar fields:
sage: f = M.scalar_field({c_xy: (x+y)^2, c_tu: t^2}, name='f') sage: s = v(f) ; s Scalar field v(f) on the 2-dimensional differentiable manifold M sage: s.display() v(f): M → ℝ on U: (x, y) ↦ 2*x^2 - 2*y^2 + 2*x + 2*y on V: (t, u) ↦ 2*t*u + 2*t
Some checks:
sage: v(f) == f.differential()(v) True sage: v(f) == f.lie_der(v) True
The result is defined on the intersection of the vector field’s domain and the scalar field’s one:
sage: s = v(f.restrict(U)) ; s Scalar field v(f) on the Open subset U of the 2-dimensional differentiable manifold M sage: s == v(f).restrict(U) True sage: s = v(f.restrict(W)) ; s Scalar field v(f) on the Open subset W of the 2-dimensional differentiable manifold M sage: s.display() v(f): W → ℝ (x, y) ↦ 2*x^2 - 2*y^2 + 2*x + 2*y (t, u) ↦ 2*t*u + 2*t sage: s = v.restrict(U)(f) ; s Scalar field v(f) on the Open subset U of the 2-dimensional differentiable manifold M sage: s.display() v(f): U → ℝ (x, y) ↦ 2*x^2 - 2*y^2 + 2*x + 2*y on W: (t, u) ↦ 2*t*u + 2*t sage: s = v.restrict(U)(f.restrict(V)) ; s Scalar field v(f) on the Open subset W of the 2-dimensional differentiable manifold M sage: s.display() v(f): W → ℝ (x, y) ↦ 2*x^2 - 2*y^2 + 2*x + 2*y (t, u) ↦ 2*t*u + 2*t
- bracket(other)#
Return the Lie bracket
[self, other]
.INPUT:
other
– aVectorField
OUTPUT:
the
VectorField
[self, other]
EXAMPLES:
sage: M = Manifold(3, 'M') sage: X.<x,y,z> = M.chart() sage: v = -X.frame()[0] + 2*X.frame()[1] - (x^2 - y)*X.frame()[2] sage: w = (z + y) * X.frame()[1] - X.frame()[2] sage: vw = v.bracket(w); vw Vector field on the 3-dimensional differentiable manifold M sage: vw.display() (-x^2 + y + 2) ∂/∂y + (-y - z) ∂/∂z
Some checks:
sage: vw == - w.bracket(v) True sage: f = M.scalar_field({X: x+y*z}) sage: vw(f) == v(w(f)) - w(v(f)) True sage: vw == w.lie_derivative(v) True
- cross(other, metric=None)#
Return the cross product of
self
with another vector field (with respect to a given metric), assuming that the domain ofself
is 3-dimensional.If
self
is a vector field \(u\) on a 3-dimensional differentiable orientable manifold \(M\) andother
is a vector field \(v\) on \(M\), the cross product (also called vector product) of \(u\) by \(v\) with respect to a pseudo-Riemannian metric \(g\) on \(M\) is the vector field \(w = u\times v\) defined by\[w^i = \epsilon^i_{\phantom{i} jk} u^j v^k = g^{il} \epsilon_{ljk} u^j v^k\]where \(\epsilon\) is the volume 3-form (Levi-Civita tensor) of \(g\) (cf.
volume_form()
)Note
The method
cross_product
is meaningful only if for vector fields on a 3-dimensional manifold.INPUT:
other
– a vector field, defined on the same domain asself
metric
– (default:None
) the pseudo-Riemannian metric \(g\) involved in the definition of the cross product; if none is provided, the domain ofself
is supposed to be endowed with a default metric (i.e. is supposed to be pseudo-Riemannian manifold, seePseudoRiemannianManifold
) and the latter is used to define the cross product
OUTPUT:
instance of
VectorField
representing the cross product ofself
byother
.
EXAMPLES:
Cross product in the Euclidean 3-space:
sage: M.<x,y,z> = EuclideanSpace() sage: u = M.vector_field(-y, x, 0, name='u') sage: v = M.vector_field(x, y, 0, name='v') sage: w = u.cross_product(v); w Vector field u x v on the Euclidean space E^3 sage: w.display() u x v = (-x^2 - y^2) e_z
A shortcut alias of
cross_product
iscross
:sage: u.cross(v) == w True
The cross product of a vector field with itself is zero:
sage: u.cross_product(u).display() u x u = 0
Cross product with respect to a metric that is not the default one:
sage: h = M.riemannian_metric('h') sage: h[1,1], h[2,2], h[3,3] = 1/(1+y^2), 1/(1+z^2), 1/(1+x^2) sage: w = u.cross_product(v, metric=h); w Vector field on the Euclidean space E^3 sage: w.display() -(x^2 + y^2)*sqrt(x^2 + 1)/(sqrt(y^2 + 1)*sqrt(z^2 + 1)) e_z
Cross product of two vector fields along a curve (arc of a helix):
sage: R.<t> = manifolds.RealLine() sage: C = M.curve((cos(t), sin(t), t), (t, 0, 2*pi), name='C') sage: u = C.tangent_vector_field() sage: u.display() C' = -sin(t) e_x + cos(t) e_y + e_z sage: I = C.domain(); I Real interval (0, 2*pi) sage: v = I.vector_field(-cos(t), sin(t), 0, dest_map=C) sage: v.display() -cos(t) e_x + sin(t) e_y sage: w = u.cross_product(v); w Vector field along the Real interval (0, 2*pi) with values on the Euclidean space E^3 sage: w.parent().destination_map() Curve C in the Euclidean space E^3 sage: w.display() -sin(t) e_x - cos(t) e_y + (2*cos(t)^2 - 1) e_z
Cross product between a vector field along the curve and a vector field on the ambient Euclidean space:
sage: e_x = M.cartesian_frame()[1] sage: w = u.cross_product(e_x); w Vector field C' x e_x along the Real interval (0, 2*pi) with values on the Euclidean space E^3 sage: w.display() C' x e_x = e_y - cos(t) e_z
- cross_product(other, metric=None)#
Return the cross product of
self
with another vector field (with respect to a given metric), assuming that the domain ofself
is 3-dimensional.If
self
is a vector field \(u\) on a 3-dimensional differentiable orientable manifold \(M\) andother
is a vector field \(v\) on \(M\), the cross product (also called vector product) of \(u\) by \(v\) with respect to a pseudo-Riemannian metric \(g\) on \(M\) is the vector field \(w = u\times v\) defined by\[w^i = \epsilon^i_{\phantom{i} jk} u^j v^k = g^{il} \epsilon_{ljk} u^j v^k\]where \(\epsilon\) is the volume 3-form (Levi-Civita tensor) of \(g\) (cf.
volume_form()
)Note
The method
cross_product
is meaningful only if for vector fields on a 3-dimensional manifold.INPUT:
other
– a vector field, defined on the same domain asself
metric
– (default:None
) the pseudo-Riemannian metric \(g\) involved in the definition of the cross product; if none is provided, the domain ofself
is supposed to be endowed with a default metric (i.e. is supposed to be pseudo-Riemannian manifold, seePseudoRiemannianManifold
) and the latter is used to define the cross product
OUTPUT:
instance of
VectorField
representing the cross product ofself
byother
.
EXAMPLES:
Cross product in the Euclidean 3-space:
sage: M.<x,y,z> = EuclideanSpace() sage: u = M.vector_field(-y, x, 0, name='u') sage: v = M.vector_field(x, y, 0, name='v') sage: w = u.cross_product(v); w Vector field u x v on the Euclidean space E^3 sage: w.display() u x v = (-x^2 - y^2) e_z
A shortcut alias of
cross_product
iscross
:sage: u.cross(v) == w True
The cross product of a vector field with itself is zero:
sage: u.cross_product(u).display() u x u = 0
Cross product with respect to a metric that is not the default one:
sage: h = M.riemannian_metric('h') sage: h[1,1], h[2,2], h[3,3] = 1/(1+y^2), 1/(1+z^2), 1/(1+x^2) sage: w = u.cross_product(v, metric=h); w Vector field on the Euclidean space E^3 sage: w.display() -(x^2 + y^2)*sqrt(x^2 + 1)/(sqrt(y^2 + 1)*sqrt(z^2 + 1)) e_z
Cross product of two vector fields along a curve (arc of a helix):
sage: R.<t> = manifolds.RealLine() sage: C = M.curve((cos(t), sin(t), t), (t, 0, 2*pi), name='C') sage: u = C.tangent_vector_field() sage: u.display() C' = -sin(t) e_x + cos(t) e_y + e_z sage: I = C.domain(); I Real interval (0, 2*pi) sage: v = I.vector_field(-cos(t), sin(t), 0, dest_map=C) sage: v.display() -cos(t) e_x + sin(t) e_y sage: w = u.cross_product(v); w Vector field along the Real interval (0, 2*pi) with values on the Euclidean space E^3 sage: w.parent().destination_map() Curve C in the Euclidean space E^3 sage: w.display() -sin(t) e_x - cos(t) e_y + (2*cos(t)^2 - 1) e_z
Cross product between a vector field along the curve and a vector field on the ambient Euclidean space:
sage: e_x = M.cartesian_frame()[1] sage: w = u.cross_product(e_x); w Vector field C' x e_x along the Real interval (0, 2*pi) with values on the Euclidean space E^3 sage: w.display() C' x e_x = e_y - cos(t) e_z
- curl(metric=None)#
Return the curl of
self
with respect to a given metric, assuming that the domain ofself
is 3-dimensional.If
self
is a vector field \(v\) on a 3-dimensional differentiable orientable manifold \(M\), the curl of \(v\) with respect to a metric \(g\) on \(M\) is the vector field defined by\[\mathrm{curl}\, v = (*(\mathrm{d} v^\flat))^\sharp\]where \(v^\flat\) is the 1-form associated to \(v\) by the metric \(g\) (see
down()
), \(*(\mathrm{d} v^\flat)\) is the Hodge dual with respect to \(g\) of the 2-form \(\mathrm{d} v^\flat\) (exterior derivative of \(v^\flat\)) (seehodge_dual()
) and \((*(\mathrm{d} v^\flat))^\sharp\) is corresponding vector field by \(g\)-duality (seeup()
).An alternative expression of the curl is
\[(\mathrm{curl}\, v)^i = \epsilon^{ijk} \nabla_j v_k\]where \(\nabla\) is the Levi-Civita connection of \(g\) (cf.
LeviCivitaConnection
) and \(\epsilon\) the volume 3-form (Levi-Civita tensor) of \(g\) (cf.volume_form()
)Note
The method
curl
is meaningful only ifself
is a vector field on a 3-dimensional manifold.INPUT:
metric
– (default:None
) the pseudo-Riemannian metric \(g\) involved in the definition of the curl; if none is provided, the domain ofself
is supposed to be endowed with a default metric (i.e. is supposed to be pseudo-Riemannian manifold, seePseudoRiemannianManifold
) and the latter is used to define the curl
OUTPUT:
instance of
VectorField
representing the curl ofself
EXAMPLES:
Curl of a vector field in the Euclidean 3-space:
sage: M.<x,y,z> = EuclideanSpace() sage: v = M.vector_field(-y, x, 0, name='v') sage: v.display() v = -y e_x + x e_y sage: s = v.curl(); s Vector field curl(v) on the Euclidean space E^3 sage: s.display() curl(v) = 2 e_z
The function
curl()
from theoperators
module can be used instead of the methodcurl()
:sage: from sage.manifolds.operators import curl sage: curl(v) == s True
If one prefers the notation
rot
overcurl
, it suffices to do:sage: from sage.manifolds.operators import curl as rot sage: rot(v) == s True
The curl of a gradient vanishes identically:
sage: f = M.scalar_field(function('F')(x,y,z)) sage: gradf = f.gradient() sage: gradf.display() d(F)/dx e_x + d(F)/dy e_y + d(F)/dz e_z sage: s = curl(gradf); s Vector field on the Euclidean space E^3 sage: s.display() 0
- dot(other, metric=None)#
Return the scalar product of
self
with another vector field (with respect to a given metric).If
self
is the vector field \(u\) and other is the vector field \(v\), the scalar product of \(u\) by \(v\) with respect to a given pseudo-Riemannian metric \(g\) is the scalar field \(s\) defined by\[s = u\cdot v = g(u,v) = g_{ij} u^i v^j\]INPUT:
other
– a vector field, defined on the same domain asself
metric
– (default:None
) the pseudo-Riemannian metric \(g\) involved in the definition of the scalar product; if none is provided, the domain ofself
is supposed to be endowed with a default metric (i.e. is supposed to be pseudo-Riemannian manifold, seePseudoRiemannianManifold
) and the latter is used to define the scalar product
OUTPUT:
instance of
DiffScalarField
representing the scalar product ofself
byother
.
EXAMPLES:
Scalar product in the Euclidean plane:
sage: M.<x,y> = EuclideanSpace() sage: u = M.vector_field(x, y, name='u') sage: v = M.vector_field(y, x, name='v') sage: s = u.dot_product(v); s Scalar field u.v on the Euclidean plane E^2 sage: s.display() u.v: E^2 → ℝ (x, y) ↦ 2*x*y
A shortcut alias of
dot_product
isdot
:sage: u.dot(v) == s True
A test of orthogonality:
sage: v[:] = -y, x sage: u.dot_product(v) == 0 True
Scalar product with respect to a metric that is not the default one:
sage: h = M.riemannian_metric('h') sage: h[1,1], h[2,2] = 1/(1+y^2), 1/(1+x^2) sage: s = u.dot_product(v, metric=h); s Scalar field h(u,v) on the Euclidean plane E^2 sage: s.display() h(u,v): E^2 → ℝ (x, y) ↦ -(x^3*y - x*y^3)/((x^2 + 1)*y^2 + x^2 + 1)
Scalar product of two vector fields along a curve (a lemniscate of Gerono):
sage: R.<t> = manifolds.RealLine() sage: C = M.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='C') sage: u = C.tangent_vector_field(name='u') sage: u.display() u = cos(t) e_x + (2*cos(t)^2 - 1) e_y sage: I = C.domain(); I Real interval (0, 2*pi) sage: v = I.vector_field(cos(t), -1, dest_map=C, name='v') sage: v.display() v = cos(t) e_x - e_y sage: s = u.dot_product(v); s Scalar field u.v on the Real interval (0, 2*pi) sage: s.display() u.v: (0, 2*pi) → ℝ t ↦ sin(t)^2
Scalar product between a vector field along the curve and a vector field on the ambient Euclidean plane:
sage: e_x = M.cartesian_frame()[1] sage: s = u.dot_product(e_x); s Scalar field u.e_x on the Real interval (0, 2*pi) sage: s.display() u.e_x: (0, 2*pi) → ℝ t ↦ cos(t)
- dot_product(other, metric=None)#
Return the scalar product of
self
with another vector field (with respect to a given metric).If
self
is the vector field \(u\) and other is the vector field \(v\), the scalar product of \(u\) by \(v\) with respect to a given pseudo-Riemannian metric \(g\) is the scalar field \(s\) defined by\[s = u\cdot v = g(u,v) = g_{ij} u^i v^j\]INPUT:
other
– a vector field, defined on the same domain asself
metric
– (default:None
) the pseudo-Riemannian metric \(g\) involved in the definition of the scalar product; if none is provided, the domain ofself
is supposed to be endowed with a default metric (i.e. is supposed to be pseudo-Riemannian manifold, seePseudoRiemannianManifold
) and the latter is used to define the scalar product
OUTPUT:
instance of
DiffScalarField
representing the scalar product ofself
byother
.
EXAMPLES:
Scalar product in the Euclidean plane:
sage: M.<x,y> = EuclideanSpace() sage: u = M.vector_field(x, y, name='u') sage: v = M.vector_field(y, x, name='v') sage: s = u.dot_product(v); s Scalar field u.v on the Euclidean plane E^2 sage: s.display() u.v: E^2 → ℝ (x, y) ↦ 2*x*y
A shortcut alias of
dot_product
isdot
:sage: u.dot(v) == s True
A test of orthogonality:
sage: v[:] = -y, x sage: u.dot_product(v) == 0 True
Scalar product with respect to a metric that is not the default one:
sage: h = M.riemannian_metric('h') sage: h[1,1], h[2,2] = 1/(1+y^2), 1/(1+x^2) sage: s = u.dot_product(v, metric=h); s Scalar field h(u,v) on the Euclidean plane E^2 sage: s.display() h(u,v): E^2 → ℝ (x, y) ↦ -(x^3*y - x*y^3)/((x^2 + 1)*y^2 + x^2 + 1)
Scalar product of two vector fields along a curve (a lemniscate of Gerono):
sage: R.<t> = manifolds.RealLine() sage: C = M.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='C') sage: u = C.tangent_vector_field(name='u') sage: u.display() u = cos(t) e_x + (2*cos(t)^2 - 1) e_y sage: I = C.domain(); I Real interval (0, 2*pi) sage: v = I.vector_field(cos(t), -1, dest_map=C, name='v') sage: v.display() v = cos(t) e_x - e_y sage: s = u.dot_product(v); s Scalar field u.v on the Real interval (0, 2*pi) sage: s.display() u.v: (0, 2*pi) → ℝ t ↦ sin(t)^2
Scalar product between a vector field along the curve and a vector field on the ambient Euclidean plane:
sage: e_x = M.cartesian_frame()[1] sage: s = u.dot_product(e_x); s Scalar field u.e_x on the Real interval (0, 2*pi) sage: s.display() u.e_x: (0, 2*pi) → ℝ t ↦ cos(t)
- norm(metric=None)#
Return the norm of
self
(with respect to a given metric).The norm of a vector field \(v\) with respect to a given pseudo-Riemannian metric \(g\) is the scalar field \(\|v\|\) defined by
\[\|v\| = \sqrt{g(v,v)}\]Note
If the metric \(g\) is not positive definite, it may be that \(\|v\|\) takes imaginary values.
INPUT:
metric
– (default:None
) the pseudo-Riemannian metric \(g\) involved in the definition of the norm; if none is provided, the domain ofself
is supposed to be endowed with a default metric (i.e. is supposed to be pseudo-Riemannian manifold, seePseudoRiemannianManifold
) and the latter is used to define the norm
OUTPUT:
instance of
DiffScalarField
representing the norm ofself
.
EXAMPLES:
Norm in the Euclidean plane:
sage: M.<x,y> = EuclideanSpace() sage: v = M.vector_field(-y, x, name='v') sage: s = v.norm(); s Scalar field |v| on the Euclidean plane E^2 sage: s.display() |v|: E^2 → ℝ (x, y) ↦ sqrt(x^2 + y^2)
The global function
norm()
can be used instead of the methodnorm()
:sage: norm(v) == s True
Norm with respect to a metric that is not the default one:
sage: h = M.riemannian_metric('h') sage: h[1,1], h[2,2] = 1/(1+y^2), 1/(1+x^2) sage: s = v.norm(metric=h); s Scalar field |v|_h on the Euclidean plane E^2 sage: s.display() |v|_h: E^2 → ℝ (x, y) ↦ sqrt((2*x^2 + 1)*y^2 + x^2)/(sqrt(x^2 + 1)*sqrt(y^2 + 1))
Norm of the tangent vector field to a curve (a lemniscate of Gerono):
sage: R.<t> = manifolds.RealLine() sage: C = M.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='C') sage: v = C.tangent_vector_field() sage: v.display() C' = cos(t) e_x + (2*cos(t)^2 - 1) e_y sage: s = v.norm(); s Scalar field |C'| on the Real interval (0, 2*pi) sage: s.display() |C'|: (0, 2*pi) → ℝ t ↦ sqrt(4*cos(t)^4 - 3*cos(t)^2 + 1)
- plot(chart=None, ambient_coords=None, mapping=None, chart_domain=None, fixed_coords=None, ranges=None, number_values=None, steps=None, parameters=None, label_axes=True, max_range=8, scale=1, color='blue', **extra_options)#
Plot the vector field in a Cartesian graph based on the coordinates of some ambient chart.
The vector field is drawn in terms of two (2D graphics) or three (3D graphics) coordinates of a given chart, called hereafter the ambient chart. The vector field’s base points \(p\) (or their images \(\Phi(p)\) by some differentiable mapping \(\Phi\)) must lie in the ambient chart’s domain.
INPUT:
chart
– (default:None
) the ambient chart (see above); ifNone
, the default chart of the vector field’s domain is usedambient_coords
– (default:None
) tuple containing the 2 or 3 coordinates of the ambient chart in terms of which the plot is performed; ifNone
, all the coordinates of the ambient chart are consideredmapping
–DiffMap
(default:None
); differentiable map \(\Phi\) providing the link between the vector field’s domain and the ambient chartchart
; ifNone
, the identity map is assumedchart_domain
– (default:None
) chart on the vector field’s domain to define the points at which vector arrows are to be plotted; ifNone
, the default chart of the vector field’s domain is usedfixed_coords
– (default:None
) dictionary with keys the coordinates ofchart_domain
that are kept fixed and with values the value of these coordinates; ifNone
, all the coordinates ofchart_domain
are usedranges
– (default:None
) dictionary with keys the coordinates ofchart_domain
to be used and values tuples(x_min, x_max)
specifying the coordinate range for the plot; ifNone
, the entire coordinate range declared during the construction ofchart_domain
is considered (with-Infinity
replaced by-max_range
and+Infinity
bymax_range
)number_values
– (default:None
) either an integer or a dictionary with keys the coordinates ofchart_domain
to be used and values the number of values of the coordinate for sampling the part of the vector field’s domain involved in the plot ; ifnumber_values
is a single integer, it represents the number of values for all coordinates; ifnumber_values
isNone
, it is set to 9 for a 2D plot and to 5 for a 3D plotsteps
– (default:None
) dictionary with keys the coordinates ofchart_domain
to be used and values the step between each constant value of the coordinate; ifNone
, the step is computed from the coordinate range (specified inranges
) andnumber_values
; on the contrary, if the step is provided for some coordinate, the corresponding number of values is deduced from it and the coordinate rangeparameters
– (default:None
) dictionary giving the numerical values of the parameters that may appear in the coordinate expression of the vector field (see example below)label_axes
– (default:True
) boolean determining whether the labels of the coordinate axes ofchart
shall be added to the graph; can be set toFalse
if the graph is 3D and must be superposed with another graphcolor
– (default: ‘blue’) color of the arrows representing the vectorsmax_range
– (default: 8) numerical value substituted to+Infinity
if the latter is the upper bound of the range of a coordinate for which the plot is performed over the entire coordinate range (i.e. for which no specific plot range has been set inranges
); similarly-max_range
is the numerical valued substituted for-Infinity
scale
– (default: 1) value by which the lengths of the arrows representing the vectors is multiplied**extra_options
– extra options for the arrow plot, likelinestyle
,width
orarrowsize
(seearrow2d()
andarrow3d()
for details)
OUTPUT:
a graphic object, either an instance of
Graphics
for a 2D plot (i.e. based on 2 coordinates ofchart
) or an instance ofGraphics3d
for a 3D plot (i.e. based on 3 coordinates ofchart
)
EXAMPLES:
Plot of a vector field on a 2-dimensional manifold:
sage: M = Manifold(2, 'M') sage: X.<x,y> = M.chart() sage: v = M.vector_field(-y, x, name='v') sage: v.display() v = -y ∂/∂x + x ∂/∂y sage: v.plot() Graphics object consisting of 80 graphics primitives
Plot with various options:
sage: v.plot(scale=0.5, color='green', linestyle='--', width=1, ....: arrowsize=6) Graphics object consisting of 80 graphics primitives
sage: v.plot(max_range=4, number_values=5, scale=0.5) Graphics object consisting of 24 graphics primitives
Plot using parallel computation:
sage: Parallelism().set(nproc=2) sage: v.plot(scale=0.5, number_values=10, linestyle='--', width=1, ....: arrowsize=6) Graphics object consisting of 100 graphics primitives
sage: Parallelism().set(nproc=1) # switch off parallelization
Plots along a line of fixed coordinate:
sage: v.plot(fixed_coords={x: -2}) Graphics object consisting of 9 graphics primitives
sage: v.plot(fixed_coords={y: 1}) Graphics object consisting of 9 graphics primitives
Let us now consider a vector field on a 4-dimensional manifold:
sage: M = Manifold(4, 'M') sage: X.<t,x,y,z> = M.chart() sage: v = M.vector_field((t/8)^2, -t*y/4, t*x/4, t*z/4, name='v') sage: v.display() v = 1/64*t^2 ∂/∂t - 1/4*t*y ∂/∂x + 1/4*t*x ∂/∂y + 1/4*t*z ∂/∂z
We cannot make a 4D plot directly:
sage: v.plot() Traceback (most recent call last): ... ValueError: the number of ambient coordinates must be either 2 or 3, not 4
Rather, we have to select some coordinates for the plot, via the argument
ambient_coords
. For instance, for a 3D plot:sage: v.plot(ambient_coords=(x, y, z), fixed_coords={t: 1}, # long time ....: number_values=4) Graphics3d Object
sage: v.plot(ambient_coords=(x, y, t), fixed_coords={z: 0}, # long time ....: ranges={x: (-2,2), y: (-2,2), t: (-1, 4)}, ....: number_values=4) Graphics3d Object
or, for a 2D plot:
sage: v.plot(ambient_coords=(x, y), fixed_coords={t: 1, z: 0}) # long time Graphics object consisting of 80 graphics primitives
sage: v.plot(ambient_coords=(x, t), fixed_coords={y: 1, z: 0}) # long time Graphics object consisting of 72 graphics primitives
An example of plot via a differential mapping: plot of a vector field tangent to a 2-sphere viewed in \(\RR^3\):
sage: S2 = Manifold(2, 'S^2') sage: U = S2.open_subset('U') # the open set covered by spherical coord. sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi') sage: R3 = Manifold(3, 'R^3') sage: X3.<x,y,z> = R3.chart() sage: F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph), ....: sin(th)*sin(ph), cos(th)]}, name='F') sage: F.display() # the standard embedding of S^2 into R^3 F: S^2 → R^3 on U: (th, ph) ↦ (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th)) sage: v = XS.frame()[1] ; v # the coordinate vector ∂/∂phi Vector field ∂/∂ph on the Open subset U of the 2-dimensional differentiable manifold S^2 sage: graph_v = v.plot(chart=X3, mapping=F, label_axes=False) sage: graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9) sage: graph_v + graph_S2 Graphics3d Object
Note that the default values of some arguments of the method
plot
are stored in the dictionaryplot.options
:sage: v.plot.options # random (dictionary output) {'color': 'blue', 'max_range': 8, 'scale': 1}
so that they can be adjusted by the user:
sage: v.plot.options['color'] = 'red'
From now on, all plots of vector fields will use red as the default color. To restore the original default options, it suffices to type:
sage: v.plot.reset()
- class sage.manifolds.differentiable.vectorfield.VectorFieldParal(vector_field_module, name=None, latex_name=None)#
Bases:
sage.tensor.modules.free_module_element.FiniteRankFreeModuleElement
,sage.manifolds.differentiable.multivectorfield.MultivectorFieldParal
,sage.manifolds.differentiable.vectorfield.VectorField
Vector field along a differentiable manifold, with values on a parallelizable manifold.
An instance of this class is a vector field along a differentiable manifold \(U\) with values on a parallelizable manifold \(M\), via a differentiable map \(\Phi: U \rightarrow M\). More precisely, given a differentiable map
\[\Phi:\ U \longrightarrow M,\]a vector field along \(U\) with values on \(M\) is a differentiable map
\[v:\ U \longrightarrow TM\](\(TM\) being the tangent bundle of \(M\)) such that
\[\forall p \in U,\ v(p) \in T_{\Phi(p)}M.\]The standard case of vector fields on a differentiable manifold corresponds to \(U = M\) and \(\Phi = \mathrm{Id}_M\). Other common cases are \(\Phi\) being an immersion and \(\Phi\) being a curve in \(M\) (\(U\) is then an open interval of \(\RR\)).
Note
If \(M\) is not parallelizable, then
VectorField
must be used instead.INPUT:
vector_field_module
– free module \(\mathfrak{X}(U,\Phi)\) of vector fields along \(U\) with values on \(M\supset\Phi(U)\)name
– (default:None
) name given to the vector fieldlatex_name
– (default:None
) LaTeX symbol to denote the vector field; if none is provided, the LaTeX symbol is set toname
EXAMPLES:
A vector field on a parallelizable 3-dimensional manifold:
sage: M = Manifold(3, 'M') sage: c_xyz.<x,y,z> = M.chart() sage: v = M.vector_field(name='V') ; v Vector field V on the 3-dimensional differentiable manifold M sage: latex(v) V
Vector fields are considered as elements of a module over the ring (algebra) of scalar fields on \(M\):
sage: v.parent() Free module X(M) of vector fields on the 3-dimensional differentiable manifold M sage: v.parent().base_ring() Algebra of differentiable scalar fields on the 3-dimensional differentiable manifold M sage: v.parent() is M.vector_field_module() True
A vector field is a tensor field of rank 1 and of type \((1,0)\):
sage: v.tensor_rank() 1 sage: v.tensor_type() (1, 0)
Components of a vector field with respect to a given frame:
sage: e = M.vector_frame('e') ; M.set_default_frame(e) sage: v[0], v[1], v[2] = (1+y, 4*x*z, 9) # components on M's default frame (e) sage: v.comp() 1-index components w.r.t. Vector frame (M, (e_0,e_1,e_2))
The totality of the components are accessed via the operator
[:]
:sage: v[:] = (1+y, 4*x*z, 9) sage: v[:] [y + 1, 4*x*z, 9]
The components are also read on the expansion on the frame
e
, as provided by the methoddisplay()
:sage: v.display() # expansion in the default frame V = (y + 1) e_0 + 4*x*z e_1 + 9 e_2
A subset of the components can be accessed by using slice notation:
sage: v[1:] = (-2, -x*y) sage: v[:] [y + 1, -2, -x*y] sage: v[:2] [y + 1, -2]
Components in another frame:
sage: f = M.vector_frame('f') sage: for i in range(3): ....: v.set_comp(f)[i] = (i+1)**3 * c_xyz[i] sage: v.comp(f)[2] 27*z sage: v[f, 2] # equivalent to above 27*z sage: v.display(f) V = x f_0 + 8*y f_1 + 27*z f_2
One can set the components at the vector definition:
sage: v = M.vector_field(1+y, 4*x*z, 9, name='V') sage: v.display() V = (y + 1) e_0 + 4*x*z e_1 + 9 e_2
If the components regard a vector frame different from the default one, the vector frame has to be specified via the argument
frame
:sage: v = M.vector_field(x, 8*y, 27*z, frame=f, name='V') sage: v.display(f) V = x f_0 + 8*y f_1 + 27*z f_2
For providing the components in various frames, one may use a dictionary:
sage: v = M.vector_field({e: [1+y, -2, -x*y], f: [x, 8*y, 27*z]}, ....: name='V') sage: v.display(e) V = (y + 1) e_0 - 2 e_1 - x*y e_2 sage: v.display(f) V = x f_0 + 8*y f_1 + 27*z f_2
It is also possible to construct a vector field from a vector of symbolic expressions (or any other iterable):
sage: v = M.vector_field(vector([1+y, 4*x*z, 9]), name='V') sage: v.display() V = (y + 1) e_0 + 4*x*z e_1 + 9 e_2
The range of the indices depends on the convention set for the manifold:
sage: M = Manifold(3, 'M', start_index=1) sage: c_xyz.<x,y,z> = M.chart() sage: e = M.vector_frame('e') ; M.set_default_frame(e) sage: v = M.vector_field(1+y, 4*x*z, 9, name='V') sage: v[0] Traceback (most recent call last): ... IndexError: index out of range: 0 not in [1, 3] sage: v[1] # OK y + 1
A vector field acts on scalar fields (derivation along the vector field):
sage: M = Manifold(2, 'M') sage: c_cart.<x,y> = M.chart() sage: f = M.scalar_field(x*y^2, name='f') sage: v = M.vector_field(-y, x, name='v') sage: v.display() v = -y ∂/∂x + x ∂/∂y sage: v(f) Scalar field v(f) on the 2-dimensional differentiable manifold M sage: v(f).expr() 2*x^2*y - y^3 sage: latex(v(f)) v\left(f\right)
Example of a vector field associated with a non-trivial map \(\Phi\); a vector field along a curve in \(M\):
sage: R = Manifold(1, 'R') sage: T.<t> = R.chart() # canonical chart on R sage: Phi = R.diff_map(M, [cos(t), sin(t)], name='Phi') ; Phi Differentiable map Phi from the 1-dimensional differentiable manifold R to the 2-dimensional differentiable manifold M sage: Phi.display() Phi: R → M t ↦ (x, y) = (cos(t), sin(t)) sage: w = R.vector_field(-sin(t), cos(t), dest_map=Phi, name='w') ; w Vector field w along the 1-dimensional differentiable manifold R with values on the 2-dimensional differentiable manifold M sage: w.parent() Free module X(R,Phi) of vector fields along the 1-dimensional differentiable manifold R mapped into the 2-dimensional differentiable manifold M sage: w.display() w = -sin(t) ∂/∂x + cos(t) ∂/∂y
Value at a given point:
sage: p = R((0,), name='p') ; p Point p on the 1-dimensional differentiable manifold R sage: w.at(p) Tangent vector w at Point Phi(p) on the 2-dimensional differentiable manifold M sage: w.at(p).display() w = ∂/∂y sage: w.at(p) == v.at(Phi(p)) True