# Vector Fields#

Given two differentiable manifolds $$U$$ and $$M$$ over the same topological field $$K$$ and a differentiable map

$\Phi:\ U \longrightarrow M,$

we define a vector field along $$U$$ with values on $$M$$ to be 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$$).

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)#

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 field

• latex_name – (default: None) LaTeX symbol to denote the vector field; if none is provided, the LaTeX symbol is set to name

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 frame eVW 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:

OUTPUT:

EXAMPLES:

sage: M = Manifold(3, 'M')
sage: X.<x,y,z> = M.chart()
sage: v = -X.frame() + 2*X.frame() - (x^2 - y)*X.frame()
sage: w = (z + y) * X.frame() - X.frame()
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 of self is 3-dimensional.

If self is a vector field $$u$$ on a 3-dimensional differentiable orientable manifold $$M$$ and other 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 as self

• metric – (default: None) the pseudo-Riemannian metric $$g$$ involved in the definition of the cross product; if none is provided, the domain of self is supposed to be endowed with a default metric (i.e. is supposed to be pseudo-Riemannian manifold, see PseudoRiemannianManifold) and the latter is used to define the cross product

OUTPUT:

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 is cross:

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()
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 of self is 3-dimensional.

If self is a vector field $$u$$ on a 3-dimensional differentiable orientable manifold $$M$$ and other 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 as self

• metric – (default: None) the pseudo-Riemannian metric $$g$$ involved in the definition of the cross product; if none is provided, the domain of self is supposed to be endowed with a default metric (i.e. is supposed to be pseudo-Riemannian manifold, see PseudoRiemannianManifold) and the latter is used to define the cross product

OUTPUT:

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 is cross:

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()
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 of self 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$$) (see hodge_dual()) and $$(*(\mathrm{d} v^\flat))^\sharp$$ is corresponding vector field by $$g$$-duality (see up()).

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 if self 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 of self is supposed to be endowed with a default metric (i.e. is supposed to be pseudo-Riemannian manifold, see PseudoRiemannianManifold) and the latter is used to define the curl

OUTPUT:

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 the operators module can be used instead of the method curl():

sage: from sage.manifolds.operators import curl
sage: curl(v) == s
True


If one prefers the notation rot over curl, 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))
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 as self

• metric – (default: None) the pseudo-Riemannian metric $$g$$ involved in the definition of the scalar product; if none is provided, the domain of self is supposed to be endowed with a default metric (i.e. is supposed to be pseudo-Riemannian manifold, see PseudoRiemannianManifold) and the latter is used to define the scalar product

OUTPUT:

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 is dot:

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()
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 as self

• metric – (default: None) the pseudo-Riemannian metric $$g$$ involved in the definition of the scalar product; if none is provided, the domain of self is supposed to be endowed with a default metric (i.e. is supposed to be pseudo-Riemannian manifold, see PseudoRiemannianManifold) and the latter is used to define the scalar product

OUTPUT:

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 is dot:

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()
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 of self is supposed to be endowed with a default metric (i.e. is supposed to be pseudo-Riemannian manifold, see PseudoRiemannianManifold) and the latter is used to define the norm

OUTPUT:

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 method norm():

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); if None, the default chart of the vector field’s domain is used

• ambient_coords – (default: None) tuple containing the 2 or 3 coordinates of the ambient chart in terms of which the plot is performed; if None, all the coordinates of the ambient chart are considered

• mappingDiffMap (default: None); differentiable map $$\Phi$$ providing the link between the vector field’s domain and the ambient chart chart; if None, the identity map is assumed

• chart_domain – (default: None) chart on the vector field’s domain to define the points at which vector arrows are to be plotted; if None, the default chart of the vector field’s domain is used

• fixed_coords – (default: None) dictionary with keys the coordinates of chart_domain that are kept fixed and with values the value of these coordinates; if None, all the coordinates of chart_domain are used

• ranges – (default: None) dictionary with keys the coordinates of chart_domain to be used and values tuples (x_min, x_max) specifying the coordinate range for the plot; if None, the entire coordinate range declared during the construction of chart_domain is considered (with -Infinity replaced by -max_range and +Infinity by max_range)

• number_values – (default: None) either an integer or a dictionary with keys the coordinates of chart_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 ; if number_values is a single integer, it represents the number of values for all coordinates; if number_values is None, it is set to 9 for a 2D plot and to 5 for a 3D plot

• steps – (default: None) dictionary with keys the coordinates of chart_domain to be used and values the step between each constant value of the coordinate; if None, the step is computed from the coordinate range (specified in ranges) and number_values; on the contrary, if the step is provided for some coordinate, the corresponding number of values is deduced from it and the coordinate range

• parameters – (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 of chart shall be added to the graph; can be set to False if the graph is 3D and must be superposed with another graph

• color – (default: ‘blue’) color of the arrows representing the vectors

• max_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 in ranges); 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, like linestyle, width or arrowsize (see arrow2d() and arrow3d() for details)

OUTPUT:

• a graphic object, either an instance of Graphics for a 2D plot (i.e. based on 2 coordinates of chart) or an instance of Graphics3d for a 3D plot (i.e. based on 3 coordinates of chart)

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() ; 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 dictionary plot.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)#

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 field

• latex_name – (default: None) LaTeX symbol to denote the vector field; if none is provided, the LaTeX symbol is set to name

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, v, v = (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 method display():

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)
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
Traceback (most recent call last):
...
IndexError: index out of range: 0 not in [1, 3]
sage: v  # 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