passagemath-symbolics 10.6.37__cp310-cp310-musllinux_1_2_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_symbolics/__init__.py +3 -0
- passagemath_symbolics-10.6.37.dist-info/METADATA +187 -0
- passagemath_symbolics-10.6.37.dist-info/RECORD +171 -0
- passagemath_symbolics-10.6.37.dist-info/WHEEL +5 -0
- passagemath_symbolics-10.6.37.dist-info/top_level.txt +3 -0
- sage/all__sagemath_symbolics.py +17 -0
- sage/calculus/all.py +14 -0
- sage/calculus/calculus.py +2826 -0
- sage/calculus/desolvers.py +1866 -0
- sage/calculus/predefined.py +51 -0
- sage/calculus/tests.py +225 -0
- sage/calculus/var.cpython-310-x86_64-linux-gnu.so +0 -0
- sage/calculus/var.pyx +401 -0
- sage/dynamics/all__sagemath_symbolics.py +6 -0
- sage/dynamics/complex_dynamics/all.py +5 -0
- sage/dynamics/complex_dynamics/mandel_julia.py +765 -0
- sage/dynamics/complex_dynamics/mandel_julia_helper.cpython-310-x86_64-linux-gnu.so +0 -0
- sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1035 -0
- sage/ext/all__sagemath_symbolics.py +1 -0
- sage/ext_data/kenzo/CP2.txt +45 -0
- sage/ext_data/kenzo/CP3.txt +349 -0
- sage/ext_data/kenzo/CP4.txt +4774 -0
- sage/ext_data/kenzo/README.txt +49 -0
- sage/ext_data/kenzo/S4.txt +20 -0
- sage/ext_data/magma/latex/latex.m +1021 -0
- sage/ext_data/magma/latex/latex.spec +1 -0
- sage/ext_data/magma/sage/basic.m +356 -0
- sage/ext_data/magma/sage/sage.spec +1 -0
- sage/ext_data/magma/spec +9 -0
- sage/geometry/all__sagemath_symbolics.py +8 -0
- sage/geometry/hyperbolic_space/all.py +5 -0
- sage/geometry/hyperbolic_space/hyperbolic_coercion.py +743 -0
- sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
- sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2409 -0
- sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
- sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1082 -0
- sage/geometry/hyperbolic_space/hyperbolic_model.py +1502 -0
- sage/geometry/hyperbolic_space/hyperbolic_point.py +621 -0
- sage/geometry/riemannian_manifolds/all.py +7 -0
- sage/geometry/riemannian_manifolds/parametrized_surface3d.py +1632 -0
- sage/geometry/riemannian_manifolds/surface3d_generators.py +461 -0
- sage/interfaces/all__sagemath_symbolics.py +1 -0
- sage/interfaces/magma.py +3017 -0
- sage/interfaces/magma_free.py +92 -0
- sage/interfaces/maple.py +1397 -0
- sage/interfaces/mathematica.py +1345 -0
- sage/interfaces/mathics.py +1312 -0
- sage/interfaces/sympy.py +1398 -0
- sage/interfaces/sympy_wrapper.py +197 -0
- sage/interfaces/tides.py +938 -0
- sage/libs/all__sagemath_symbolics.py +6 -0
- sage/manifolds/all.py +7 -0
- sage/manifolds/calculus_method.py +555 -0
- sage/manifolds/catalog.py +437 -0
- sage/manifolds/chart.py +4019 -0
- sage/manifolds/chart_func.py +3419 -0
- sage/manifolds/continuous_map.py +2183 -0
- sage/manifolds/continuous_map_image.py +155 -0
- sage/manifolds/differentiable/affine_connection.py +2475 -0
- sage/manifolds/differentiable/all.py +1 -0
- sage/manifolds/differentiable/automorphismfield.py +1383 -0
- sage/manifolds/differentiable/automorphismfield_group.py +604 -0
- sage/manifolds/differentiable/bundle_connection.py +1445 -0
- sage/manifolds/differentiable/characteristic_cohomology_class.py +1840 -0
- sage/manifolds/differentiable/chart.py +1241 -0
- sage/manifolds/differentiable/curve.py +1028 -0
- sage/manifolds/differentiable/de_rham_cohomology.py +541 -0
- sage/manifolds/differentiable/degenerate.py +559 -0
- sage/manifolds/differentiable/degenerate_submanifold.py +1671 -0
- sage/manifolds/differentiable/diff_form.py +1658 -0
- sage/manifolds/differentiable/diff_form_module.py +1062 -0
- sage/manifolds/differentiable/diff_map.py +1315 -0
- sage/manifolds/differentiable/differentiable_submanifold.py +291 -0
- sage/manifolds/differentiable/examples/all.py +1 -0
- sage/manifolds/differentiable/examples/euclidean.py +2517 -0
- sage/manifolds/differentiable/examples/real_line.py +897 -0
- sage/manifolds/differentiable/examples/sphere.py +1186 -0
- sage/manifolds/differentiable/examples/symplectic_space.py +187 -0
- sage/manifolds/differentiable/examples/symplectic_space_test.py +40 -0
- sage/manifolds/differentiable/integrated_curve.py +4035 -0
- sage/manifolds/differentiable/levi_civita_connection.py +841 -0
- sage/manifolds/differentiable/manifold.py +4254 -0
- sage/manifolds/differentiable/manifold_homset.py +1826 -0
- sage/manifolds/differentiable/metric.py +3032 -0
- sage/manifolds/differentiable/mixed_form.py +1507 -0
- sage/manifolds/differentiable/mixed_form_algebra.py +559 -0
- sage/manifolds/differentiable/multivector_module.py +800 -0
- sage/manifolds/differentiable/multivectorfield.py +1520 -0
- sage/manifolds/differentiable/poisson_tensor.py +268 -0
- sage/manifolds/differentiable/pseudo_riemannian.py +755 -0
- sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +1839 -0
- sage/manifolds/differentiable/scalarfield.py +1343 -0
- sage/manifolds/differentiable/scalarfield_algebra.py +472 -0
- sage/manifolds/differentiable/symplectic_form.py +910 -0
- sage/manifolds/differentiable/symplectic_form_test.py +220 -0
- sage/manifolds/differentiable/tangent_space.py +412 -0
- sage/manifolds/differentiable/tangent_vector.py +616 -0
- sage/manifolds/differentiable/tensorfield.py +4665 -0
- sage/manifolds/differentiable/tensorfield_module.py +963 -0
- sage/manifolds/differentiable/tensorfield_paral.py +2450 -0
- sage/manifolds/differentiable/tensorfield_paral_test.py +16 -0
- sage/manifolds/differentiable/vector_bundle.py +1728 -0
- sage/manifolds/differentiable/vectorfield.py +1717 -0
- sage/manifolds/differentiable/vectorfield_module.py +2445 -0
- sage/manifolds/differentiable/vectorframe.py +1832 -0
- sage/manifolds/family.py +270 -0
- sage/manifolds/local_frame.py +1490 -0
- sage/manifolds/manifold.py +3090 -0
- sage/manifolds/manifold_homset.py +452 -0
- sage/manifolds/operators.py +359 -0
- sage/manifolds/point.py +994 -0
- sage/manifolds/scalarfield.py +3718 -0
- sage/manifolds/scalarfield_algebra.py +629 -0
- sage/manifolds/section.py +3111 -0
- sage/manifolds/section_module.py +831 -0
- sage/manifolds/structure.py +229 -0
- sage/manifolds/subset.py +2764 -0
- sage/manifolds/subsets/all.py +1 -0
- sage/manifolds/subsets/closure.py +131 -0
- sage/manifolds/subsets/pullback.py +885 -0
- sage/manifolds/topological_submanifold.py +891 -0
- sage/manifolds/trivialization.py +733 -0
- sage/manifolds/utilities.py +1348 -0
- sage/manifolds/vector_bundle.py +1342 -0
- sage/manifolds/vector_bundle_fiber.py +332 -0
- sage/manifolds/vector_bundle_fiber_element.py +111 -0
- sage/matrix/all__sagemath_symbolics.py +1 -0
- sage/matrix/matrix_symbolic_dense.cpython-310-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix_symbolic_dense.pxd +6 -0
- sage/matrix/matrix_symbolic_dense.pyx +1022 -0
- sage/matrix/matrix_symbolic_sparse.cpython-310-x86_64-linux-gnu.so +0 -0
- sage/matrix/matrix_symbolic_sparse.pxd +6 -0
- sage/matrix/matrix_symbolic_sparse.pyx +1029 -0
- sage/modules/all__sagemath_symbolics.py +1 -0
- sage/modules/vector_callable_symbolic_dense.py +105 -0
- sage/modules/vector_symbolic_dense.py +116 -0
- sage/modules/vector_symbolic_sparse.py +118 -0
- sage/rings/all__sagemath_symbolics.py +4 -0
- sage/rings/asymptotic/all.py +6 -0
- sage/rings/asymptotic/asymptotic_expansion_generators.py +1485 -0
- sage/rings/asymptotic/asymptotic_ring.py +4858 -0
- sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +4153 -0
- sage/rings/asymptotic/growth_group.py +5373 -0
- sage/rings/asymptotic/growth_group_cartesian.py +1400 -0
- sage/rings/asymptotic/term_monoid.py +5237 -0
- sage/rings/function_field/all__sagemath_symbolics.py +2 -0
- sage/rings/polynomial/all__sagemath_symbolics.py +1 -0
- sage/symbolic/all.py +15 -0
- sage/symbolic/assumptions.py +985 -0
- sage/symbolic/benchmark.py +93 -0
- sage/symbolic/callable.py +459 -0
- sage/symbolic/complexity_measures.py +35 -0
- sage/symbolic/constants.py +1287 -0
- sage/symbolic/expression_conversion_algebraic.py +310 -0
- sage/symbolic/expression_conversion_sympy.py +317 -0
- sage/symbolic/expression_conversions.py +1713 -0
- sage/symbolic/function_factory.py +355 -0
- sage/symbolic/integration/all.py +1 -0
- sage/symbolic/integration/external.py +270 -0
- sage/symbolic/integration/integral.py +1115 -0
- sage/symbolic/maxima_wrapper.py +162 -0
- sage/symbolic/operators.py +267 -0
- sage/symbolic/random_tests.py +462 -0
- sage/symbolic/relation.py +1907 -0
- sage/symbolic/ring.cpython-310-x86_64-linux-gnu.so +0 -0
- sage/symbolic/ring.pxd +5 -0
- sage/symbolic/ring.pyx +1396 -0
- sage/symbolic/subring.py +1025 -0
- sage/symbolic/symengine.py +19 -0
- sage/symbolic/tests.py +40 -0
- sage/symbolic/units.py +1470 -0
|
@@ -0,0 +1,1717 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-symbolics
|
|
2
|
+
r"""
|
|
3
|
+
Vector Fields
|
|
4
|
+
|
|
5
|
+
Given two differentiable manifolds `U` and `M` over the same topological field
|
|
6
|
+
`K` and a differentiable map
|
|
7
|
+
|
|
8
|
+
.. MATH::
|
|
9
|
+
|
|
10
|
+
\Phi:\ U \longrightarrow M,
|
|
11
|
+
|
|
12
|
+
we define a *vector field along* `U` *with values on* `M` to be a
|
|
13
|
+
differentiable map
|
|
14
|
+
|
|
15
|
+
.. MATH::
|
|
16
|
+
|
|
17
|
+
v:\ U \longrightarrow TM
|
|
18
|
+
|
|
19
|
+
(`TM` being the tangent bundle of `M`) such that
|
|
20
|
+
|
|
21
|
+
.. MATH::
|
|
22
|
+
|
|
23
|
+
\forall p \in U,\ v(p) \in T_{\Phi(p)}M.
|
|
24
|
+
|
|
25
|
+
The standard case of vector fields *on* a differentiable manifold corresponds
|
|
26
|
+
to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are `\Phi`
|
|
27
|
+
being an immersion and `\Phi` being a curve in `M` (`U` is then an open
|
|
28
|
+
interval of `\RR`).
|
|
29
|
+
|
|
30
|
+
Vector fields are implemented via two classes: :class:`VectorFieldParal` and
|
|
31
|
+
:class:`VectorField`, depending respectively whether the manifold `M`
|
|
32
|
+
is parallelizable or not, i.e. whether the bundle `TM` is trivial or not.
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
AUTHORS:
|
|
36
|
+
|
|
37
|
+
- Eric Gourgoulhon, Michal Bejger (2013-2015) : initial version
|
|
38
|
+
- Marco Mancini (2015): parallelization of vector field plots
|
|
39
|
+
- Travis Scrimshaw (2016): review tweaks
|
|
40
|
+
- Eric Gourgoulhon (2017): vector fields inherit from multivector fields
|
|
41
|
+
- Eric Gourgoulhon (2018): dot and cross products, operators norm and curl
|
|
42
|
+
|
|
43
|
+
REFERENCES:
|
|
44
|
+
|
|
45
|
+
- [KN1963]_
|
|
46
|
+
- [Lee2013]_
|
|
47
|
+
- [ONe1983]_
|
|
48
|
+
- [BG1988]_
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
# *****************************************************************************
|
|
52
|
+
# Copyright (C) 2015, 2017 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
|
|
53
|
+
# Copyright (C) 2015 Michal Bejger <bejger@camk.edu.pl>
|
|
54
|
+
# Copyright (C) 2015 Marco Mancini <marco.mancini@obspm.fr>
|
|
55
|
+
# Copyright (C) 2016 Travis Scrimshaw <tscrimsh@umn.edu>
|
|
56
|
+
#
|
|
57
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
58
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
59
|
+
# the License, or (at your option) any later version.
|
|
60
|
+
# https://www.gnu.org/licenses/
|
|
61
|
+
# *****************************************************************************
|
|
62
|
+
|
|
63
|
+
from sage.manifolds.differentiable.multivectorfield import (
|
|
64
|
+
MultivectorField,
|
|
65
|
+
MultivectorFieldParal,
|
|
66
|
+
)
|
|
67
|
+
from sage.misc.decorators import options
|
|
68
|
+
from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class VectorField(MultivectorField):
|
|
72
|
+
r"""
|
|
73
|
+
Vector field along a differentiable manifold.
|
|
74
|
+
|
|
75
|
+
An instance of this class is a vector field along a differentiable
|
|
76
|
+
manifold `U` with values on a differentiable manifold `M`, via a
|
|
77
|
+
differentiable map `U \rightarrow M`. More precisely, given a
|
|
78
|
+
differentiable map
|
|
79
|
+
|
|
80
|
+
.. MATH::
|
|
81
|
+
|
|
82
|
+
\Phi:\ U \longrightarrow M,
|
|
83
|
+
|
|
84
|
+
a *vector field along* `U` *with values on* `M` is a differentiable map
|
|
85
|
+
|
|
86
|
+
.. MATH::
|
|
87
|
+
|
|
88
|
+
v:\ U \longrightarrow TM
|
|
89
|
+
|
|
90
|
+
(`TM` being the tangent bundle of `M`) such that
|
|
91
|
+
|
|
92
|
+
.. MATH::
|
|
93
|
+
|
|
94
|
+
\forall p \in U,\ v(p) \in T_{\Phi(p)}M.
|
|
95
|
+
|
|
96
|
+
The standard case of vector fields *on* a differentiable manifold
|
|
97
|
+
corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases are
|
|
98
|
+
`\Phi` being an immersion and `\Phi` being a curve in `M` (`U` is then an
|
|
99
|
+
open interval of `\RR`).
|
|
100
|
+
|
|
101
|
+
.. NOTE::
|
|
102
|
+
|
|
103
|
+
If `M` is parallelizable, then
|
|
104
|
+
:class:`~sage.manifolds.differentiable.vectorfield.VectorFieldParal`
|
|
105
|
+
*must* be used instead.
|
|
106
|
+
|
|
107
|
+
INPUT:
|
|
108
|
+
|
|
109
|
+
- ``vector_field_module`` -- module `\mathfrak{X}(U,\Phi)` of vector
|
|
110
|
+
fields along `U` with values on `M\supset\Phi(U)`
|
|
111
|
+
- ``name`` -- (default: ``None``) name given to the vector field
|
|
112
|
+
- ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the vector
|
|
113
|
+
field; if none is provided, the LaTeX symbol is set to ``name``
|
|
114
|
+
|
|
115
|
+
EXAMPLES:
|
|
116
|
+
|
|
117
|
+
A vector field on a non-parallelizable 2-dimensional manifold::
|
|
118
|
+
|
|
119
|
+
sage: M = Manifold(2, 'M')
|
|
120
|
+
sage: U = M.open_subset('U') ; V = M.open_subset('V')
|
|
121
|
+
sage: M.declare_union(U,V) # M is the union of U and V
|
|
122
|
+
sage: c_xy.<x,y> = U.chart() ; c_tu.<t,u> = V.chart()
|
|
123
|
+
sage: transf = c_xy.transition_map(c_tu, (x+y, x-y), intersection_name='W',
|
|
124
|
+
....: restrictions1= x>0, restrictions2= t+u>0)
|
|
125
|
+
sage: inv = transf.inverse()
|
|
126
|
+
sage: W = U.intersection(V)
|
|
127
|
+
sage: eU = c_xy.frame() ; eV = c_tu.frame()
|
|
128
|
+
sage: c_tuW = c_tu.restrict(W) ; eVW = c_tuW.frame()
|
|
129
|
+
sage: v = M.vector_field(name='v') ; v
|
|
130
|
+
Vector field v on the 2-dimensional differentiable manifold M
|
|
131
|
+
sage: v.parent()
|
|
132
|
+
Module X(M) of vector fields on the 2-dimensional differentiable
|
|
133
|
+
manifold M
|
|
134
|
+
|
|
135
|
+
The vector field is first defined on the domain `U` by means of its
|
|
136
|
+
components with respect to the frame ``eU``::
|
|
137
|
+
|
|
138
|
+
sage: v[eU,:] = [-y, 1+x]
|
|
139
|
+
|
|
140
|
+
The components with respect to the frame ``eV`` are then deduced
|
|
141
|
+
by continuation of the components with respect to the frame ``eVW``
|
|
142
|
+
on the domain `W = U \cap V`, expressed in terms on the coordinates
|
|
143
|
+
covering `V`::
|
|
144
|
+
|
|
145
|
+
sage: v[eV,0] = v[eVW,0,c_tuW].expr()
|
|
146
|
+
sage: v[eV,1] = v[eVW,1,c_tuW].expr()
|
|
147
|
+
|
|
148
|
+
At this stage, the vector field is fully defined on the whole manifold::
|
|
149
|
+
|
|
150
|
+
sage: v.display(eU)
|
|
151
|
+
v = -y ∂/∂x + (x + 1) ∂/∂y
|
|
152
|
+
sage: v.display(eV)
|
|
153
|
+
v = (u + 1) ∂/∂t + (-t - 1) ∂/∂u
|
|
154
|
+
|
|
155
|
+
The vector field acting on scalar fields::
|
|
156
|
+
|
|
157
|
+
sage: f = M.scalar_field({c_xy: (x+y)^2, c_tu: t^2}, name='f')
|
|
158
|
+
sage: s = v(f) ; s
|
|
159
|
+
Scalar field v(f) on the 2-dimensional differentiable manifold M
|
|
160
|
+
sage: s.display()
|
|
161
|
+
v(f): M → ℝ
|
|
162
|
+
on U: (x, y) ↦ 2*x^2 - 2*y^2 + 2*x + 2*y
|
|
163
|
+
on V: (t, u) ↦ 2*t*u + 2*t
|
|
164
|
+
|
|
165
|
+
Some checks::
|
|
166
|
+
|
|
167
|
+
sage: v(f) == f.differential()(v)
|
|
168
|
+
True
|
|
169
|
+
sage: v(f) == f.lie_der(v)
|
|
170
|
+
True
|
|
171
|
+
|
|
172
|
+
The result is defined on the intersection of the vector field's
|
|
173
|
+
domain and the scalar field's one::
|
|
174
|
+
|
|
175
|
+
sage: s = v(f.restrict(U)) ; s
|
|
176
|
+
Scalar field v(f) on the Open subset U of the 2-dimensional
|
|
177
|
+
differentiable manifold M
|
|
178
|
+
sage: s == v(f).restrict(U)
|
|
179
|
+
True
|
|
180
|
+
sage: s = v(f.restrict(W)) ; s
|
|
181
|
+
Scalar field v(f) on the Open subset W of the 2-dimensional
|
|
182
|
+
differentiable manifold M
|
|
183
|
+
sage: s.display()
|
|
184
|
+
v(f): W → ℝ
|
|
185
|
+
(x, y) ↦ 2*x^2 - 2*y^2 + 2*x + 2*y
|
|
186
|
+
(t, u) ↦ 2*t*u + 2*t
|
|
187
|
+
sage: s = v.restrict(U)(f) ; s
|
|
188
|
+
Scalar field v(f) on the Open subset U of the 2-dimensional
|
|
189
|
+
differentiable manifold M
|
|
190
|
+
sage: s.display()
|
|
191
|
+
v(f): U → ℝ
|
|
192
|
+
(x, y) ↦ 2*x^2 - 2*y^2 + 2*x + 2*y
|
|
193
|
+
on W: (t, u) ↦ 2*t*u + 2*t
|
|
194
|
+
sage: s = v.restrict(U)(f.restrict(V)) ; s
|
|
195
|
+
Scalar field v(f) on the Open subset W of the 2-dimensional
|
|
196
|
+
differentiable manifold M
|
|
197
|
+
sage: s.display()
|
|
198
|
+
v(f): W → ℝ
|
|
199
|
+
(x, y) ↦ 2*x^2 - 2*y^2 + 2*x + 2*y
|
|
200
|
+
(t, u) ↦ 2*t*u + 2*t
|
|
201
|
+
"""
|
|
202
|
+
def __init__(self, vector_field_module, name=None, latex_name=None):
|
|
203
|
+
r"""
|
|
204
|
+
Construct a vector field with values on a non-parallelizable manifold.
|
|
205
|
+
|
|
206
|
+
TESTS:
|
|
207
|
+
|
|
208
|
+
Construction via ``parent.element_class``, and not via a direct call
|
|
209
|
+
to ``VectorField``, to fit with the category framework::
|
|
210
|
+
|
|
211
|
+
sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2
|
|
212
|
+
sage: U = M.open_subset('U') # complement of the North pole
|
|
213
|
+
sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
|
|
214
|
+
sage: V = M.open_subset('V') # complement of the South pole
|
|
215
|
+
sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole
|
|
216
|
+
sage: M.declare_union(U,V) # S^2 is the union of U and V
|
|
217
|
+
sage: XM = M.vector_field_module()
|
|
218
|
+
sage: a = XM.element_class(XM, name='a'); a
|
|
219
|
+
Vector field a on the 2-dimensional differentiable manifold M
|
|
220
|
+
sage: a[c_xy.frame(),:] = [x, y]
|
|
221
|
+
sage: a[c_uv.frame(),:] = [-u, -v]
|
|
222
|
+
sage: TestSuite(a).run(skip='_test_pickling')
|
|
223
|
+
|
|
224
|
+
Construction with ``DifferentiableManifold.vector_field``::
|
|
225
|
+
|
|
226
|
+
sage: a1 = M.vector_field(name='a'); a1
|
|
227
|
+
Vector field a on the 2-dimensional differentiable manifold M
|
|
228
|
+
sage: type(a1) == type(a)
|
|
229
|
+
True
|
|
230
|
+
|
|
231
|
+
.. TODO::
|
|
232
|
+
|
|
233
|
+
Fix ``_test_pickling`` (in the superclass :class:`TensorField`).
|
|
234
|
+
"""
|
|
235
|
+
MultivectorField.__init__(self, vector_field_module, 1, name=name,
|
|
236
|
+
latex_name=latex_name)
|
|
237
|
+
# Initialization of derived quantities:
|
|
238
|
+
MultivectorField._init_derived(self)
|
|
239
|
+
# Initialization of list of quantities depending on self:
|
|
240
|
+
self._init_dependencies()
|
|
241
|
+
|
|
242
|
+
def _repr_(self):
|
|
243
|
+
r"""
|
|
244
|
+
Return a string representation of ``self``.
|
|
245
|
+
|
|
246
|
+
TESTS::
|
|
247
|
+
|
|
248
|
+
sage: M = Manifold(2, 'M')
|
|
249
|
+
sage: v = M.vector_field(name='v')
|
|
250
|
+
sage: v._repr_()
|
|
251
|
+
'Vector field v on the 2-dimensional differentiable manifold M'
|
|
252
|
+
sage: repr(v) # indirect doctest
|
|
253
|
+
'Vector field v on the 2-dimensional differentiable manifold M'
|
|
254
|
+
sage: v # indirect doctest
|
|
255
|
+
Vector field v on the 2-dimensional differentiable manifold M
|
|
256
|
+
"""
|
|
257
|
+
description = "Vector field "
|
|
258
|
+
if self._name is not None:
|
|
259
|
+
description += self._name + " "
|
|
260
|
+
return self._final_repr(description)
|
|
261
|
+
|
|
262
|
+
def _new_instance(self):
|
|
263
|
+
r"""
|
|
264
|
+
Create an instance of the same class as ``self`` on the same module.
|
|
265
|
+
|
|
266
|
+
TESTS::
|
|
267
|
+
|
|
268
|
+
sage: M = Manifold(2, 'M')
|
|
269
|
+
sage: v = M.vector_field(name='v')
|
|
270
|
+
sage: u = v._new_instance(); u
|
|
271
|
+
Vector field on the 2-dimensional differentiable manifold M
|
|
272
|
+
sage: u.parent() is v.parent()
|
|
273
|
+
True
|
|
274
|
+
"""
|
|
275
|
+
return type(self)(self._vmodule)
|
|
276
|
+
|
|
277
|
+
def _init_dependencies(self):
|
|
278
|
+
r"""
|
|
279
|
+
Initialize list of quantities that depend on ``self``.
|
|
280
|
+
|
|
281
|
+
TESTS::
|
|
282
|
+
|
|
283
|
+
sage: M = Manifold(2, 'M')
|
|
284
|
+
sage: v = M.vector_field(name='v')
|
|
285
|
+
sage: v._init_dependencies()
|
|
286
|
+
"""
|
|
287
|
+
self._lie_der_along_self = {}
|
|
288
|
+
|
|
289
|
+
def _del_dependencies(self):
|
|
290
|
+
r"""
|
|
291
|
+
Clear list of quantities that depend on ``self``.
|
|
292
|
+
|
|
293
|
+
TESTS::
|
|
294
|
+
|
|
295
|
+
sage: M = Manifold(2, 'M')
|
|
296
|
+
sage: v = M.vector_field(name='v')
|
|
297
|
+
sage: v._del_dependencies()
|
|
298
|
+
"""
|
|
299
|
+
if self._lie_der_along_self != {}:
|
|
300
|
+
for tens in self._lie_der_along_self.values():
|
|
301
|
+
del tens._lie_derivatives[id(self)]
|
|
302
|
+
self._lie_der_along_self.clear()
|
|
303
|
+
|
|
304
|
+
def __call__(self, scalar):
|
|
305
|
+
r"""
|
|
306
|
+
Action on a scalar field (or on a 1-form).
|
|
307
|
+
|
|
308
|
+
INPUT:
|
|
309
|
+
|
|
310
|
+
- ``scalar`` -- scalar field `f`
|
|
311
|
+
|
|
312
|
+
OUTPUT:
|
|
313
|
+
|
|
314
|
+
- scalar field representing the derivative of `f` along the vector
|
|
315
|
+
field, i.e. `v^i \frac{\partial f}{\partial x^i}`
|
|
316
|
+
|
|
317
|
+
TESTS::
|
|
318
|
+
|
|
319
|
+
sage: M = Manifold(2, 'M') # the 2-dimensional sphere S^2
|
|
320
|
+
sage: U = M.open_subset('U') # complement of the North pole
|
|
321
|
+
sage: c_xy.<x,y> = U.chart() # stereographic coordinates from the North pole
|
|
322
|
+
sage: V = M.open_subset('V') # complement of the South pole
|
|
323
|
+
sage: c_uv.<u,v> = V.chart() # stereographic coordinates from the South pole
|
|
324
|
+
sage: M.declare_union(U,V) # S^2 is the union of U and V
|
|
325
|
+
sage: a = M.vector_field({c_xy.frame(): [x, y],
|
|
326
|
+
....: c_uv.frame(): [-u, -v]}, name='a')
|
|
327
|
+
sage: f = M.scalar_field({c_xy: atan(x^2+y^2),
|
|
328
|
+
....: c_uv: pi/2-atan(u^2+v^2)}, name='f')
|
|
329
|
+
sage: s = a.__call__(f); s
|
|
330
|
+
Scalar field a(f) on the 2-dimensional differentiable manifold M
|
|
331
|
+
sage: s.display()
|
|
332
|
+
a(f): M → ℝ
|
|
333
|
+
on U: (x, y) ↦ 2*(x^2 + y^2)/(x^4 + 2*x^2*y^2 + y^4 + 1)
|
|
334
|
+
on V: (u, v) ↦ 2*(u^2 + v^2)/(u^4 + 2*u^2*v^2 + v^4 + 1)
|
|
335
|
+
sage: s == f.differential()(a)
|
|
336
|
+
True
|
|
337
|
+
"""
|
|
338
|
+
if scalar._tensor_type == (0,1):
|
|
339
|
+
# This is actually the action of the vector field on a 1-form,
|
|
340
|
+
# as a tensor field of type (1,0):
|
|
341
|
+
return scalar(self)
|
|
342
|
+
if scalar._tensor_type != (0,0):
|
|
343
|
+
raise TypeError("the argument must be a scalar field")
|
|
344
|
+
resu = scalar.differential()(self)
|
|
345
|
+
if not resu.is_immutable():
|
|
346
|
+
if self._name is not None and scalar._name is not None:
|
|
347
|
+
name = f"{self._name}({scalar._name})"
|
|
348
|
+
else:
|
|
349
|
+
name = None
|
|
350
|
+
if self._latex_name is not None and scalar._latex_name is not None:
|
|
351
|
+
latex_name = fr"{self._latex_name}\left({scalar._latex_name}\right)"
|
|
352
|
+
else:
|
|
353
|
+
latex_name = None
|
|
354
|
+
resu.set_name(name=name, latex_name=latex_name)
|
|
355
|
+
return resu
|
|
356
|
+
|
|
357
|
+
@options(max_range=8, scale=1, color='blue')
|
|
358
|
+
def plot(self, chart=None, ambient_coords=None, mapping=None,
|
|
359
|
+
chart_domain=None, fixed_coords=None, ranges=None,
|
|
360
|
+
number_values=None, steps=None,
|
|
361
|
+
parameters=None, label_axes=True, **extra_options):
|
|
362
|
+
r"""
|
|
363
|
+
Plot the vector field in a Cartesian graph based on the coordinates
|
|
364
|
+
of some ambient chart.
|
|
365
|
+
|
|
366
|
+
The vector field is drawn in terms of two (2D graphics) or three
|
|
367
|
+
(3D graphics) coordinates of a given chart, called hereafter the
|
|
368
|
+
*ambient chart*.
|
|
369
|
+
The vector field's base points `p` (or their images `\Phi(p)` by some
|
|
370
|
+
differentiable mapping `\Phi`) must lie in the ambient chart's domain.
|
|
371
|
+
|
|
372
|
+
INPUT:
|
|
373
|
+
|
|
374
|
+
- ``chart`` -- (default: ``None``) the ambient chart (see above); if
|
|
375
|
+
``None``, the default chart of the vector field's domain is used
|
|
376
|
+
|
|
377
|
+
- ``ambient_coords`` -- (default: ``None``) tuple containing the 2
|
|
378
|
+
or 3 coordinates of the ambient chart in terms of which the plot
|
|
379
|
+
is performed; if ``None``, all the coordinates of the ambient
|
|
380
|
+
chart are considered
|
|
381
|
+
|
|
382
|
+
- ``mapping`` -- :class:`~sage.manifolds.differentiable.diff_map.DiffMap`
|
|
383
|
+
(default: ``None``); differentiable map `\Phi` providing the link
|
|
384
|
+
between the vector field's domain and the ambient chart ``chart``;
|
|
385
|
+
if ``None``, the identity map is assumed
|
|
386
|
+
|
|
387
|
+
- ``chart_domain`` -- (default: ``None``) chart on the vector field's
|
|
388
|
+
domain to define the points at which vector arrows are to be plotted;
|
|
389
|
+
if ``None``, the default chart of the vector field's domain is used
|
|
390
|
+
|
|
391
|
+
- ``fixed_coords`` -- (default: ``None``) dictionary with keys the
|
|
392
|
+
coordinates of ``chart_domain`` that are kept fixed and with values
|
|
393
|
+
the value of these coordinates; if ``None``, all the coordinates of
|
|
394
|
+
``chart_domain`` are used
|
|
395
|
+
|
|
396
|
+
- ``ranges`` -- (default: ``None``) dictionary with keys the
|
|
397
|
+
coordinates of ``chart_domain`` to be used and values tuples
|
|
398
|
+
``(x_min, x_max)`` specifying the coordinate range for the plot;
|
|
399
|
+
if ``None``, the entire coordinate range declared during the
|
|
400
|
+
construction of ``chart_domain`` is considered (with ``-Infinity``
|
|
401
|
+
replaced by ``-max_range`` and ``+Infinity`` by ``max_range``)
|
|
402
|
+
|
|
403
|
+
- ``number_values`` -- (default: ``None``) either an integer or a
|
|
404
|
+
dictionary with keys the coordinates of ``chart_domain`` to be
|
|
405
|
+
used and values the number of values of the coordinate for sampling
|
|
406
|
+
the part of the vector field's domain involved in the plot ; if
|
|
407
|
+
``number_values`` is a single integer, it represents the number of
|
|
408
|
+
values for all coordinates; if ``number_values`` is ``None``, it is
|
|
409
|
+
set to 9 for a 2D plot and to 5 for a 3D plot
|
|
410
|
+
|
|
411
|
+
- ``steps`` -- (default: ``None``) dictionary with keys the
|
|
412
|
+
coordinates of ``chart_domain`` to be used and values the step
|
|
413
|
+
between each constant value of the coordinate; if ``None``, the
|
|
414
|
+
step is computed from the coordinate range (specified in ``ranges``)
|
|
415
|
+
and ``number_values``; on the contrary, if the step is provided
|
|
416
|
+
for some coordinate, the corresponding number of values is deduced
|
|
417
|
+
from it and the coordinate range
|
|
418
|
+
|
|
419
|
+
- ``parameters`` -- (default: ``None``) dictionary giving the numerical
|
|
420
|
+
values of the parameters that may appear in the coordinate expression
|
|
421
|
+
of the vector field (see example below)
|
|
422
|
+
|
|
423
|
+
- ``label_axes`` -- boolean (default: ``True``); determining whether
|
|
424
|
+
the labels of the coordinate axes of ``chart`` shall be added to
|
|
425
|
+
the graph; can be set to ``False`` if the graph is 3D and must be
|
|
426
|
+
superposed with another graph
|
|
427
|
+
|
|
428
|
+
- ``color`` -- (default: ``'blue'``) color of the arrows representing
|
|
429
|
+
the vectors
|
|
430
|
+
|
|
431
|
+
- ``max_range`` -- (default: 8) numerical value substituted to
|
|
432
|
+
``+Infinity`` if the latter is the upper bound of the range of a
|
|
433
|
+
coordinate for which the plot is performed over the entire coordinate
|
|
434
|
+
range (i.e. for which no specific plot range has been set in
|
|
435
|
+
``ranges``); similarly ``-max_range`` is the numerical valued
|
|
436
|
+
substituted for ``-Infinity``
|
|
437
|
+
|
|
438
|
+
- ``scale`` -- (default: 1) value by which the lengths of the arrows
|
|
439
|
+
representing the vectors is multiplied
|
|
440
|
+
|
|
441
|
+
- ``**extra_options`` -- extra options for the arrow plot, like
|
|
442
|
+
``linestyle``, ``width`` or ``arrowsize`` (see
|
|
443
|
+
:func:`~sage.plot.arrow.arrow2d` and
|
|
444
|
+
:func:`~sage.plot.plot3d.shapes.arrow3d` for details)
|
|
445
|
+
|
|
446
|
+
OUTPUT:
|
|
447
|
+
|
|
448
|
+
- a graphic object, either an instance of
|
|
449
|
+
:class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on
|
|
450
|
+
2 coordinates of ``chart``) or an instance of
|
|
451
|
+
:class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e.
|
|
452
|
+
based on 3 coordinates of ``chart``)
|
|
453
|
+
|
|
454
|
+
EXAMPLES:
|
|
455
|
+
|
|
456
|
+
Plot of a vector field on a 2-dimensional manifold::
|
|
457
|
+
|
|
458
|
+
sage: M = Manifold(2, 'M')
|
|
459
|
+
sage: X.<x,y> = M.chart()
|
|
460
|
+
sage: v = M.vector_field(-y, x, name='v')
|
|
461
|
+
sage: v.display()
|
|
462
|
+
v = -y ∂/∂x + x ∂/∂y
|
|
463
|
+
sage: v.plot() # needs sage.plot
|
|
464
|
+
Graphics object consisting of 80 graphics primitives
|
|
465
|
+
|
|
466
|
+
.. PLOT::
|
|
467
|
+
|
|
468
|
+
M = Manifold(2, 'M')
|
|
469
|
+
X = M.chart('x y'); x, y = X[:]
|
|
470
|
+
v = M.vector_field(-y, x, name='v')
|
|
471
|
+
g = v.plot()
|
|
472
|
+
sphinx_plot(g)
|
|
473
|
+
|
|
474
|
+
Plot with various options::
|
|
475
|
+
|
|
476
|
+
sage: v.plot(scale=0.5, color='green', linestyle='--', width=1, # needs sage.plot
|
|
477
|
+
....: arrowsize=6)
|
|
478
|
+
Graphics object consisting of 80 graphics primitives
|
|
479
|
+
|
|
480
|
+
.. PLOT::
|
|
481
|
+
|
|
482
|
+
M = Manifold(2, 'M')
|
|
483
|
+
X = M.chart('x y'); x, y = X[:]
|
|
484
|
+
v = M.vector_field(-y, x, name='v')
|
|
485
|
+
g = v.plot(scale=0.5, color='green', linestyle='--', width=1, arrowsize=6)
|
|
486
|
+
sphinx_plot(g)
|
|
487
|
+
|
|
488
|
+
::
|
|
489
|
+
|
|
490
|
+
sage: v.plot(max_range=4, number_values=5, scale=0.5) # needs sage.plot
|
|
491
|
+
Graphics object consisting of 24 graphics primitives
|
|
492
|
+
|
|
493
|
+
.. PLOT::
|
|
494
|
+
|
|
495
|
+
M = Manifold(2, 'M')
|
|
496
|
+
X = M.chart('x y'); x, y = X[:]
|
|
497
|
+
v = M.vector_field(-y, x, name='v')
|
|
498
|
+
g = v.plot(max_range=4, number_values=5, scale=0.5)
|
|
499
|
+
sphinx_plot(g)
|
|
500
|
+
|
|
501
|
+
Plot using parallel computation::
|
|
502
|
+
|
|
503
|
+
sage: Parallelism().set(nproc=2)
|
|
504
|
+
sage: v.plot(scale=0.5, number_values=10, linestyle='--', width=1, # needs sage.plot
|
|
505
|
+
....: arrowsize=6)
|
|
506
|
+
Graphics object consisting of 100 graphics primitives
|
|
507
|
+
|
|
508
|
+
.. PLOT::
|
|
509
|
+
|
|
510
|
+
M = Manifold(2, 'M')
|
|
511
|
+
X = M.chart('x y'); x, y = X[:]
|
|
512
|
+
v = M.vector_field(-y, x, name='v')
|
|
513
|
+
g = v.plot(scale=0.5, number_values=10, linestyle='--', width=1, arrowsize=6)
|
|
514
|
+
sphinx_plot(g)
|
|
515
|
+
|
|
516
|
+
::
|
|
517
|
+
|
|
518
|
+
sage: Parallelism().set(nproc=1) # switch off parallelization
|
|
519
|
+
|
|
520
|
+
Plots along a line of fixed coordinate::
|
|
521
|
+
|
|
522
|
+
sage: v.plot(fixed_coords={x: -2}) # needs sage.plot
|
|
523
|
+
Graphics object consisting of 9 graphics primitives
|
|
524
|
+
|
|
525
|
+
.. PLOT::
|
|
526
|
+
|
|
527
|
+
M = Manifold(2, 'M')
|
|
528
|
+
X = M.chart('x y'); x, y = X[:]
|
|
529
|
+
v = M.vector_field(-y, x, name='v')
|
|
530
|
+
g = v.plot(fixed_coords={x: -2})
|
|
531
|
+
sphinx_plot(g)
|
|
532
|
+
|
|
533
|
+
::
|
|
534
|
+
|
|
535
|
+
sage: v.plot(fixed_coords={y: 1}) # needs sage.plot
|
|
536
|
+
Graphics object consisting of 9 graphics primitives
|
|
537
|
+
|
|
538
|
+
.. PLOT::
|
|
539
|
+
|
|
540
|
+
M = Manifold(2, 'M')
|
|
541
|
+
X = M.chart('x y'); x, y = X[:]
|
|
542
|
+
v = M.vector_field(-y, x, name='v')
|
|
543
|
+
g = v.plot(fixed_coords={y: 1})
|
|
544
|
+
sphinx_plot(g)
|
|
545
|
+
|
|
546
|
+
Let us now consider a vector field on a 4-dimensional manifold::
|
|
547
|
+
|
|
548
|
+
sage: M = Manifold(4, 'M')
|
|
549
|
+
sage: X.<t,x,y,z> = M.chart()
|
|
550
|
+
sage: v = M.vector_field((t/8)^2, -t*y/4, t*x/4, t*z/4, name='v')
|
|
551
|
+
sage: v.display()
|
|
552
|
+
v = 1/64*t^2 ∂/∂t - 1/4*t*y ∂/∂x + 1/4*t*x ∂/∂y + 1/4*t*z ∂/∂z
|
|
553
|
+
|
|
554
|
+
We cannot make a 4D plot directly::
|
|
555
|
+
|
|
556
|
+
sage: v.plot() # needs sage.plot
|
|
557
|
+
Traceback (most recent call last):
|
|
558
|
+
...
|
|
559
|
+
ValueError: the number of ambient coordinates must be either 2 or 3, not 4
|
|
560
|
+
|
|
561
|
+
Rather, we have to select some coordinates for the plot, via
|
|
562
|
+
the argument ``ambient_coords``. For instance, for a 3D plot::
|
|
563
|
+
|
|
564
|
+
sage: v.plot(ambient_coords=(x, y, z), fixed_coords={t: 1}, # long time, needs sage.plot
|
|
565
|
+
....: number_values=4)
|
|
566
|
+
Graphics3d Object
|
|
567
|
+
|
|
568
|
+
.. PLOT::
|
|
569
|
+
|
|
570
|
+
M = Manifold(4, 'M')
|
|
571
|
+
X = M.chart('t x y z') ; t,x,y,z = X[:]
|
|
572
|
+
v = M.vector_field((t/8)**2, -t*y/4, t*x/4, t*z/4, name='v')
|
|
573
|
+
sphinx_plot(v.plot(ambient_coords=(x, y, z), fixed_coords={t: 1},
|
|
574
|
+
number_values=4))
|
|
575
|
+
|
|
576
|
+
::
|
|
577
|
+
|
|
578
|
+
sage: v.plot(ambient_coords=(x, y, t), fixed_coords={z: 0}, # long time, needs sage.plot
|
|
579
|
+
....: ranges={x: (-2,2), y: (-2,2), t: (-1, 4)},
|
|
580
|
+
....: number_values=4)
|
|
581
|
+
Graphics3d Object
|
|
582
|
+
|
|
583
|
+
.. PLOT::
|
|
584
|
+
|
|
585
|
+
M = Manifold(4, 'M')
|
|
586
|
+
X = M.chart('t x y z'); t,x,y,z = X[:]
|
|
587
|
+
v = M.vector_field((t/8)**2, -t*y/4, t*x/4, t*z/4, name='v')
|
|
588
|
+
sphinx_plot(v.plot(ambient_coords=(x, y, t), fixed_coords={z: 0},
|
|
589
|
+
ranges={x: (-2,2), y: (-2,2), t: (-1, 4)},
|
|
590
|
+
number_values=4))
|
|
591
|
+
|
|
592
|
+
or, for a 2D plot::
|
|
593
|
+
|
|
594
|
+
sage: v.plot(ambient_coords=(x, y), fixed_coords={t: 1, z: 0}) # long time, needs sage.plot
|
|
595
|
+
Graphics object consisting of 80 graphics primitives
|
|
596
|
+
|
|
597
|
+
.. PLOT::
|
|
598
|
+
|
|
599
|
+
M = Manifold(4, 'M')
|
|
600
|
+
X = M.chart('t x y z'); t,x,y,z = X[:]
|
|
601
|
+
v = M.vector_field((t/8)**2, -t*y/4, t*x/4, t*z/4, name='v')
|
|
602
|
+
g = v.plot(ambient_coords=(x, y), fixed_coords={t: 1, z: 0})
|
|
603
|
+
sphinx_plot(g)
|
|
604
|
+
|
|
605
|
+
::
|
|
606
|
+
|
|
607
|
+
sage: v.plot(ambient_coords=(x, t), fixed_coords={y: 1, z: 0}) # long time, needs sage.plot
|
|
608
|
+
Graphics object consisting of 72 graphics primitives
|
|
609
|
+
|
|
610
|
+
.. PLOT::
|
|
611
|
+
|
|
612
|
+
M = Manifold(4, 'M')
|
|
613
|
+
X = M.chart('t x y z'); t,x,y,z = X[:]
|
|
614
|
+
v = M.vector_field((t/8)**2, -t*y/4, t*x/4, t*z/4, name='v')
|
|
615
|
+
g = v.plot(ambient_coords=(x, t), fixed_coords={y: 1, z: 0})
|
|
616
|
+
sphinx_plot(g)
|
|
617
|
+
|
|
618
|
+
An example of plot via a differential mapping: plot of a vector field
|
|
619
|
+
tangent to a 2-sphere viewed in `\RR^3`::
|
|
620
|
+
|
|
621
|
+
sage: S2 = Manifold(2, 'S^2')
|
|
622
|
+
sage: U = S2.open_subset('U') # the open set covered by spherical coord.
|
|
623
|
+
sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
|
|
624
|
+
sage: R3 = Manifold(3, 'R^3')
|
|
625
|
+
sage: X3.<x,y,z> = R3.chart()
|
|
626
|
+
sage: F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph),
|
|
627
|
+
....: sin(th)*sin(ph), cos(th)]}, name='F')
|
|
628
|
+
sage: F.display() # the standard embedding of S^2 into R^3
|
|
629
|
+
F: S^2 → R^3
|
|
630
|
+
on U: (th, ph) ↦ (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th))
|
|
631
|
+
sage: v = XS.frame()[1] ; v # the coordinate vector ∂/∂phi
|
|
632
|
+
Vector field ∂/∂ph on the Open subset U of the 2-dimensional
|
|
633
|
+
differentiable manifold S^2
|
|
634
|
+
sage: graph_v = v.plot(chart=X3, mapping=F, label_axes=False) # needs sage.plot
|
|
635
|
+
sage: graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9) # needs sage.plot
|
|
636
|
+
sage: graph_v + graph_S2 # needs sage.plot
|
|
637
|
+
Graphics3d Object
|
|
638
|
+
|
|
639
|
+
.. PLOT::
|
|
640
|
+
|
|
641
|
+
S2 = Manifold(2, 'S^2')
|
|
642
|
+
U = S2.open_subset('U')
|
|
643
|
+
XS = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi')
|
|
644
|
+
th, ph = XS[:]
|
|
645
|
+
R3 = Manifold(3, 'R^3')
|
|
646
|
+
X3 = R3.chart('x y z')
|
|
647
|
+
F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph), sin(th)*sin(ph),
|
|
648
|
+
cos(th)]}, name='F')
|
|
649
|
+
v = XS.frame()[1]
|
|
650
|
+
graph_v = v.plot(chart=X3, mapping=F, label_axes=False)
|
|
651
|
+
graph_S2 = XS.plot(chart=X3, mapping=F, number_values=9)
|
|
652
|
+
sphinx_plot(graph_v + graph_S2)
|
|
653
|
+
|
|
654
|
+
Note that the default values of some arguments of the method ``plot``
|
|
655
|
+
are stored in the dictionary ``plot.options``::
|
|
656
|
+
|
|
657
|
+
sage: v.plot.options # random (dictionary output)
|
|
658
|
+
{'color': 'blue', 'max_range': 8, 'scale': 1}
|
|
659
|
+
|
|
660
|
+
so that they can be adjusted by the user::
|
|
661
|
+
|
|
662
|
+
sage: v.plot.options['color'] = 'red'
|
|
663
|
+
|
|
664
|
+
From now on, all plots of vector fields will use red as the default
|
|
665
|
+
color. To restore the original default options, it suffices to type::
|
|
666
|
+
|
|
667
|
+
sage: v.plot.reset()
|
|
668
|
+
"""
|
|
669
|
+
from sage.manifolds.chart import RealChart
|
|
670
|
+
from sage.manifolds.utilities import set_axes_labels
|
|
671
|
+
from sage.misc.functional import numerical_approx
|
|
672
|
+
from sage.misc.latex import latex
|
|
673
|
+
from sage.parallel.decorate import parallel
|
|
674
|
+
from sage.parallel.parallelism import Parallelism
|
|
675
|
+
from sage.plot.graphics import Graphics
|
|
676
|
+
from sage.rings.infinity import Infinity
|
|
677
|
+
|
|
678
|
+
#
|
|
679
|
+
# 1/ Treatment of input parameters
|
|
680
|
+
# -----------------------------
|
|
681
|
+
max_range = extra_options.pop("max_range")
|
|
682
|
+
scale = extra_options.pop("scale")
|
|
683
|
+
color = extra_options.pop("color")
|
|
684
|
+
if chart is None:
|
|
685
|
+
chart = self._domain.default_chart()
|
|
686
|
+
elif not isinstance(chart, RealChart):
|
|
687
|
+
raise TypeError("{} is not a chart on a real ".format(chart) +
|
|
688
|
+
"manifold")
|
|
689
|
+
if chart_domain is None:
|
|
690
|
+
chart_domain = self._domain.default_chart()
|
|
691
|
+
elif not isinstance(chart_domain, RealChart):
|
|
692
|
+
raise TypeError("{} is not a chart on a ".format(chart_domain) +
|
|
693
|
+
"real manifold")
|
|
694
|
+
elif not chart_domain.domain().is_subset(self._domain):
|
|
695
|
+
raise ValueError("the domain of {} is not ".format(chart_domain) +
|
|
696
|
+
"included in the domain of {}".format(self))
|
|
697
|
+
coords_full = tuple(chart_domain[:]) # all coordinates of chart_domain
|
|
698
|
+
if fixed_coords is None:
|
|
699
|
+
coords = coords_full
|
|
700
|
+
else:
|
|
701
|
+
fixed_coord_list = fixed_coords.keys()
|
|
702
|
+
coords = []
|
|
703
|
+
for coord in coords_full:
|
|
704
|
+
if coord not in fixed_coord_list:
|
|
705
|
+
coords.append(coord)
|
|
706
|
+
coords = tuple(coords)
|
|
707
|
+
if ambient_coords is None:
|
|
708
|
+
ambient_coords = chart[:]
|
|
709
|
+
elif not isinstance(ambient_coords, tuple):
|
|
710
|
+
ambient_coords = tuple(ambient_coords)
|
|
711
|
+
nca = len(ambient_coords)
|
|
712
|
+
if nca != 2 and nca != 3:
|
|
713
|
+
raise ValueError("the number of ambient coordinates must be " +
|
|
714
|
+
"either 2 or 3, not {}".format(nca))
|
|
715
|
+
if ranges is None:
|
|
716
|
+
ranges = {}
|
|
717
|
+
ranges0 = {}
|
|
718
|
+
for coord in coords:
|
|
719
|
+
if coord in ranges:
|
|
720
|
+
ranges0[coord] = (numerical_approx(ranges[coord][0]),
|
|
721
|
+
numerical_approx(ranges[coord][1]))
|
|
722
|
+
else:
|
|
723
|
+
bounds = chart_domain._bounds[coords_full.index(coord)]
|
|
724
|
+
xmin0 = bounds[0][0]
|
|
725
|
+
xmax0 = bounds[1][0]
|
|
726
|
+
if xmin0 == -Infinity:
|
|
727
|
+
xmin = numerical_approx(-max_range)
|
|
728
|
+
elif bounds[0][1]:
|
|
729
|
+
xmin = numerical_approx(xmin0)
|
|
730
|
+
else:
|
|
731
|
+
xmin = numerical_approx(xmin0 + 1.e-3)
|
|
732
|
+
if xmax0 == Infinity:
|
|
733
|
+
xmax = numerical_approx(max_range)
|
|
734
|
+
elif bounds[1][1]:
|
|
735
|
+
xmax = numerical_approx(xmax0)
|
|
736
|
+
else:
|
|
737
|
+
xmax = numerical_approx(xmax0 - 1.e-3)
|
|
738
|
+
ranges0[coord] = (xmin, xmax)
|
|
739
|
+
ranges = ranges0
|
|
740
|
+
if number_values is None:
|
|
741
|
+
if nca == 2: # 2D plot
|
|
742
|
+
number_values = 9
|
|
743
|
+
else: # 3D plot
|
|
744
|
+
number_values = 5
|
|
745
|
+
if not isinstance(number_values, dict):
|
|
746
|
+
number_values0 = {}
|
|
747
|
+
for coord in coords:
|
|
748
|
+
number_values0[coord] = number_values
|
|
749
|
+
number_values = number_values0
|
|
750
|
+
if steps is None:
|
|
751
|
+
steps = {}
|
|
752
|
+
for coord in coords:
|
|
753
|
+
if coord not in steps:
|
|
754
|
+
steps[coord] = (ranges[coord][1] - ranges[coord][0]) / \
|
|
755
|
+
(number_values[coord]-1)
|
|
756
|
+
else:
|
|
757
|
+
number_values[coord] = 1 + int(
|
|
758
|
+
(ranges[coord][1] - ranges[coord][0]) / steps[coord])
|
|
759
|
+
#
|
|
760
|
+
# 2/ Plots
|
|
761
|
+
# -----
|
|
762
|
+
dom = chart_domain.domain()
|
|
763
|
+
vector = self.restrict(dom)
|
|
764
|
+
if vector.parent().destination_map() is dom.identity_map():
|
|
765
|
+
if mapping is not None:
|
|
766
|
+
vector = mapping.pushforward(vector)
|
|
767
|
+
mapping = None
|
|
768
|
+
nc = len(coords_full)
|
|
769
|
+
ncp = len(coords)
|
|
770
|
+
xx = [0] * nc
|
|
771
|
+
if fixed_coords is not None:
|
|
772
|
+
if len(fixed_coords) != nc - ncp:
|
|
773
|
+
raise ValueError("bad number of fixed coordinates")
|
|
774
|
+
for fc, val in fixed_coords.items():
|
|
775
|
+
xx[coords_full.index(fc)] = val
|
|
776
|
+
ind_coord = []
|
|
777
|
+
for coord in coords:
|
|
778
|
+
ind_coord.append(coords_full.index(coord))
|
|
779
|
+
|
|
780
|
+
resu = Graphics()
|
|
781
|
+
ind = [0] * ncp
|
|
782
|
+
ind_max = [0] * ncp
|
|
783
|
+
ind_max[0] = number_values[coords[0]]
|
|
784
|
+
xmin = [ranges[cd][0] for cd in coords]
|
|
785
|
+
step_tab = [steps[cd] for cd in coords]
|
|
786
|
+
|
|
787
|
+
nproc = Parallelism().get('tensor')
|
|
788
|
+
if nproc != 1 and nca == 2:
|
|
789
|
+
# parallel plot construct : Only for 2D plot (at moment) !
|
|
790
|
+
|
|
791
|
+
# creation of the list of parameters
|
|
792
|
+
list_xx = []
|
|
793
|
+
|
|
794
|
+
while ind != ind_max:
|
|
795
|
+
for i in range(ncp):
|
|
796
|
+
xx[ind_coord[i]] = xmin[i] + ind[i] * step_tab[i]
|
|
797
|
+
|
|
798
|
+
if chart_domain.valid_coordinates(*xx, tolerance=1e-13,
|
|
799
|
+
parameters=parameters):
|
|
800
|
+
|
|
801
|
+
# needed a xx*1 to copy the list by value
|
|
802
|
+
list_xx.append(xx*1)
|
|
803
|
+
|
|
804
|
+
# Next index:
|
|
805
|
+
ret = 1
|
|
806
|
+
for pos in range(ncp-1,-1,-1):
|
|
807
|
+
imax = number_values[coords[pos]] - 1
|
|
808
|
+
if ind[pos] != imax:
|
|
809
|
+
ind[pos] += ret
|
|
810
|
+
ret = 0
|
|
811
|
+
elif ret == 1:
|
|
812
|
+
if pos == 0:
|
|
813
|
+
ind[pos] = imax + 1 # end point reached
|
|
814
|
+
else:
|
|
815
|
+
ind[pos] = 0
|
|
816
|
+
ret = 1
|
|
817
|
+
|
|
818
|
+
lol = lambda lst, sz: [lst[i:i+sz] for i in range(0, len(lst), sz)]
|
|
819
|
+
ind_step = max(1, int(len(list_xx)/nproc/2))
|
|
820
|
+
local_list = lol(list_xx,ind_step)
|
|
821
|
+
|
|
822
|
+
# definition of the list of input parameters
|
|
823
|
+
listParalInput = [(vector, dom, ind_part,
|
|
824
|
+
chart_domain, chart,
|
|
825
|
+
ambient_coords, mapping,
|
|
826
|
+
scale, color, parameters,
|
|
827
|
+
extra_options)
|
|
828
|
+
for ind_part in local_list]
|
|
829
|
+
|
|
830
|
+
# definition of the parallel function
|
|
831
|
+
@parallel(p_iter='multiprocessing', ncpus=nproc)
|
|
832
|
+
def add_point_plot(vector, dom, xx_list, chart_domain, chart,
|
|
833
|
+
ambient_coords, mapping, scale, color,
|
|
834
|
+
parameters, extra_options):
|
|
835
|
+
count = 0
|
|
836
|
+
for xx in xx_list:
|
|
837
|
+
point = dom(xx, chart=chart_domain)
|
|
838
|
+
part = vector.at(point).plot(chart=chart,
|
|
839
|
+
ambient_coords=ambient_coords,
|
|
840
|
+
mapping=mapping,scale=scale,
|
|
841
|
+
color=color, print_label=False,
|
|
842
|
+
parameters=parameters,
|
|
843
|
+
**extra_options)
|
|
844
|
+
if count == 0:
|
|
845
|
+
local_resu = part
|
|
846
|
+
else:
|
|
847
|
+
local_resu += part
|
|
848
|
+
count += 1
|
|
849
|
+
return local_resu
|
|
850
|
+
|
|
851
|
+
# parallel execution and reconstruction of the plot
|
|
852
|
+
for ii, val in add_point_plot(listParalInput):
|
|
853
|
+
resu += val
|
|
854
|
+
|
|
855
|
+
else:
|
|
856
|
+
# sequential plot
|
|
857
|
+
while ind != ind_max:
|
|
858
|
+
for i in range(ncp):
|
|
859
|
+
xx[ind_coord[i]] = xmin[i] + ind[i]*step_tab[i]
|
|
860
|
+
if chart_domain.valid_coordinates(*xx, tolerance=1e-13,
|
|
861
|
+
parameters=parameters):
|
|
862
|
+
point = dom(xx, chart=chart_domain)
|
|
863
|
+
resu += vector.at(point).plot(chart=chart,
|
|
864
|
+
ambient_coords=ambient_coords,
|
|
865
|
+
mapping=mapping, scale=scale,
|
|
866
|
+
color=color, print_label=False,
|
|
867
|
+
parameters=parameters,
|
|
868
|
+
**extra_options)
|
|
869
|
+
# Next index:
|
|
870
|
+
ret = 1
|
|
871
|
+
for pos in range(ncp-1, -1, -1):
|
|
872
|
+
imax = number_values[coords[pos]] - 1
|
|
873
|
+
if ind[pos] != imax:
|
|
874
|
+
ind[pos] += ret
|
|
875
|
+
ret = 0
|
|
876
|
+
elif ret == 1:
|
|
877
|
+
if pos == 0:
|
|
878
|
+
ind[pos] = imax + 1 # end point reached
|
|
879
|
+
else:
|
|
880
|
+
ind[pos] = 0
|
|
881
|
+
ret = 1
|
|
882
|
+
|
|
883
|
+
if label_axes:
|
|
884
|
+
if nca == 2: # 2D graphic
|
|
885
|
+
# We update the dictionary _extra_kwds (options to be passed
|
|
886
|
+
# to show()), instead of using the method
|
|
887
|
+
# Graphics.axes_labels() since the latter is not robust w.r.t.
|
|
888
|
+
# graph addition
|
|
889
|
+
resu._extra_kwds['axes_labels'] = [r'$'+latex(ac)+r'$'
|
|
890
|
+
for ac in ambient_coords]
|
|
891
|
+
else: # 3D graphic
|
|
892
|
+
labels = [str(ac) for ac in ambient_coords]
|
|
893
|
+
resu = set_axes_labels(resu, *labels)
|
|
894
|
+
return resu
|
|
895
|
+
|
|
896
|
+
def bracket(self, other):
|
|
897
|
+
"""
|
|
898
|
+
Return the Lie bracket ``[self, other]``.
|
|
899
|
+
|
|
900
|
+
INPUT:
|
|
901
|
+
|
|
902
|
+
- ``other`` -- a :class:`VectorField`
|
|
903
|
+
|
|
904
|
+
OUTPUT: the :class:`VectorField` ``[self, other]``
|
|
905
|
+
|
|
906
|
+
EXAMPLES::
|
|
907
|
+
|
|
908
|
+
sage: M = Manifold(3, 'M')
|
|
909
|
+
sage: X.<x,y,z> = M.chart()
|
|
910
|
+
sage: v = -X.frame()[0] + 2*X.frame()[1] - (x^2 - y)*X.frame()[2]
|
|
911
|
+
sage: w = (z + y) * X.frame()[1] - X.frame()[2]
|
|
912
|
+
sage: vw = v.bracket(w); vw
|
|
913
|
+
Vector field on the 3-dimensional differentiable manifold M
|
|
914
|
+
sage: vw.display()
|
|
915
|
+
(-x^2 + y + 2) ∂/∂y + (-y - z) ∂/∂z
|
|
916
|
+
|
|
917
|
+
Some checks::
|
|
918
|
+
|
|
919
|
+
sage: vw == - w.bracket(v)
|
|
920
|
+
True
|
|
921
|
+
sage: f = M.scalar_field({X: x+y*z})
|
|
922
|
+
sage: vw(f) == v(w(f)) - w(v(f))
|
|
923
|
+
True
|
|
924
|
+
sage: vw == w.lie_derivative(v)
|
|
925
|
+
True
|
|
926
|
+
"""
|
|
927
|
+
# Call of the Schouten-Nijenhuis bracket
|
|
928
|
+
return MultivectorField.bracket(self, other)
|
|
929
|
+
|
|
930
|
+
def curl(self, metric=None):
|
|
931
|
+
r"""
|
|
932
|
+
Return the curl of ``self`` with respect to a given metric, assuming
|
|
933
|
+
that the domain of ``self`` is 3-dimensional.
|
|
934
|
+
|
|
935
|
+
If ``self`` is a vector field `v` on a 3-dimensional differentiable
|
|
936
|
+
orientable manifold `M`, the curl of `v` with respect to a metric `g`
|
|
937
|
+
on `M` is the vector field defined by
|
|
938
|
+
|
|
939
|
+
.. MATH::
|
|
940
|
+
|
|
941
|
+
\mathrm{curl}\, v = (*(\mathrm{d} v^\flat))^\sharp
|
|
942
|
+
|
|
943
|
+
where `v^\flat` is the 1-form associated to `v` by the metric `g` (see
|
|
944
|
+
:meth:`~sage.manifolds.differentiable.tensorfield.TensorField.down`),
|
|
945
|
+
`*(\mathrm{d} v^\flat)` is the Hodge dual with respect to `g` of the
|
|
946
|
+
2-form `\mathrm{d} v^\flat` (exterior derivative of `v^\flat`) (see
|
|
947
|
+
:meth:`~sage.manifolds.differentiable.diff_form.DiffForm.hodge_dual`)
|
|
948
|
+
and
|
|
949
|
+
`(*(\mathrm{d} v^\flat))^\sharp` is corresponding vector field by
|
|
950
|
+
`g`-duality (see
|
|
951
|
+
:meth:`~sage.manifolds.differentiable.tensorfield.TensorField.up`).
|
|
952
|
+
|
|
953
|
+
An alternative expression of the curl is
|
|
954
|
+
|
|
955
|
+
.. MATH::
|
|
956
|
+
|
|
957
|
+
(\mathrm{curl}\, v)^i = \epsilon^{ijk} \nabla_j v_k
|
|
958
|
+
|
|
959
|
+
where `\nabla` is the Levi-Civita connection of `g` (cf.
|
|
960
|
+
:class:`~sage.manifolds.differentiable.levi_civita_connection.LeviCivitaConnection`)
|
|
961
|
+
and `\epsilon` the volume 3-form (Levi-Civita tensor) of `g` (cf.
|
|
962
|
+
:meth:`~sage.manifolds.differentiable.metric.PseudoRiemannianMetric.volume_form`)
|
|
963
|
+
|
|
964
|
+
.. NOTE::
|
|
965
|
+
|
|
966
|
+
The method ``curl`` is meaningful only if ``self`` is a vector
|
|
967
|
+
field on a 3-dimensional manifold.
|
|
968
|
+
|
|
969
|
+
INPUT:
|
|
970
|
+
|
|
971
|
+
- ``metric`` -- (default: ``None``) the pseudo-Riemannian metric `g`
|
|
972
|
+
involved in the definition of the curl; if none is provided, the
|
|
973
|
+
domain of ``self`` is supposed to be endowed with a default metric
|
|
974
|
+
(i.e. is supposed to be pseudo-Riemannian manifold, see
|
|
975
|
+
:class:`~sage.manifolds.differentiable.pseudo_riemannian.PseudoRiemannianManifold`)
|
|
976
|
+
and the latter is used to define the curl
|
|
977
|
+
|
|
978
|
+
OUTPUT: instance of :class:`VectorField` representing the curl of ``self``
|
|
979
|
+
|
|
980
|
+
EXAMPLES:
|
|
981
|
+
|
|
982
|
+
Curl of a vector field in the Euclidean 3-space::
|
|
983
|
+
|
|
984
|
+
sage: M.<x,y,z> = EuclideanSpace()
|
|
985
|
+
sage: v = M.vector_field(-y, x, 0, name='v')
|
|
986
|
+
sage: v.display()
|
|
987
|
+
v = -y e_x + x e_y
|
|
988
|
+
sage: s = v.curl(); s
|
|
989
|
+
Vector field curl(v) on the Euclidean space E^3
|
|
990
|
+
sage: s.display()
|
|
991
|
+
curl(v) = 2 e_z
|
|
992
|
+
|
|
993
|
+
The function :func:`~sage.manifolds.operators.curl` from the
|
|
994
|
+
:mod:`~sage.manifolds.operators` module can be used instead of the
|
|
995
|
+
method :meth:`curl`::
|
|
996
|
+
|
|
997
|
+
sage: from sage.manifolds.operators import curl
|
|
998
|
+
sage: curl(v) == s
|
|
999
|
+
True
|
|
1000
|
+
|
|
1001
|
+
If one prefers the notation ``rot`` over ``curl``, it suffices to do::
|
|
1002
|
+
|
|
1003
|
+
sage: from sage.manifolds.operators import curl as rot
|
|
1004
|
+
sage: rot(v) == s
|
|
1005
|
+
True
|
|
1006
|
+
|
|
1007
|
+
The curl of a gradient vanishes identically::
|
|
1008
|
+
|
|
1009
|
+
sage: f = M.scalar_field(function('F')(x,y,z))
|
|
1010
|
+
sage: gradf = f.gradient()
|
|
1011
|
+
sage: gradf.display()
|
|
1012
|
+
d(F)/dx e_x + d(F)/dy e_y + d(F)/dz e_z
|
|
1013
|
+
sage: s = curl(gradf); s
|
|
1014
|
+
Vector field on the Euclidean space E^3
|
|
1015
|
+
sage: s.display()
|
|
1016
|
+
0
|
|
1017
|
+
"""
|
|
1018
|
+
if self._domain.dim() < 3:
|
|
1019
|
+
raise ValueError("the curl is not defined in dimension lower " +
|
|
1020
|
+
"than 3")
|
|
1021
|
+
default_metric = metric is None
|
|
1022
|
+
if default_metric:
|
|
1023
|
+
metric = self._domain.metric()
|
|
1024
|
+
der = self.down(metric).exterior_derivative() # 2-form d(v^\flat)
|
|
1025
|
+
resu = der.hodge_dual(metric).up(metric)
|
|
1026
|
+
if self._name is not None:
|
|
1027
|
+
if default_metric:
|
|
1028
|
+
resu._name = "curl({})".format(self._name)
|
|
1029
|
+
resu._latex_name = r"\mathrm{curl}\left(" + self._latex_name + \
|
|
1030
|
+
r"\right)"
|
|
1031
|
+
else:
|
|
1032
|
+
resu._name = "curl_{}({})".format(metric._name, self._name)
|
|
1033
|
+
resu._latex_name = r"\mathrm{curl}_{" + metric._latex_name + \
|
|
1034
|
+
r"}\left(" + self._latex_name + r"\right)"
|
|
1035
|
+
# The name is propagated to possible restrictions of self:
|
|
1036
|
+
for restrict in resu._restrictions.values():
|
|
1037
|
+
restrict.set_name(resu._name, latex_name=resu._latex_name)
|
|
1038
|
+
return resu
|
|
1039
|
+
|
|
1040
|
+
def dot_product(self, other, metric=None):
|
|
1041
|
+
r"""
|
|
1042
|
+
Return the scalar product of ``self`` with another vector field (with
|
|
1043
|
+
respect to a given metric).
|
|
1044
|
+
|
|
1045
|
+
If ``self`` is the vector field `u` and other is the vector field `v`,
|
|
1046
|
+
the *scalar product of* `u` *by* `v` with respect to a given
|
|
1047
|
+
pseudo-Riemannian metric `g` is the scalar field `s` defined by
|
|
1048
|
+
|
|
1049
|
+
.. MATH::
|
|
1050
|
+
|
|
1051
|
+
s = u\cdot v = g(u,v) = g_{ij} u^i v^j
|
|
1052
|
+
|
|
1053
|
+
INPUT:
|
|
1054
|
+
|
|
1055
|
+
- ``other`` -- a vector field, defined on the same domain as ``self``
|
|
1056
|
+
- ``metric`` -- (default: ``None``) the pseudo-Riemannian metric `g`
|
|
1057
|
+
involved in the definition of the scalar product; if none is
|
|
1058
|
+
provided, the domain of ``self`` is supposed to be endowed with a
|
|
1059
|
+
default metric (i.e. is supposed to be pseudo-Riemannian manifold,
|
|
1060
|
+
see
|
|
1061
|
+
:class:`~sage.manifolds.differentiable.pseudo_riemannian.PseudoRiemannianManifold`)
|
|
1062
|
+
and the latter is used to define the scalar product
|
|
1063
|
+
|
|
1064
|
+
OUTPUT:
|
|
1065
|
+
|
|
1066
|
+
- instance of
|
|
1067
|
+
:class:`~sage.manifolds.differentiable.scalarfield.DiffScalarField`
|
|
1068
|
+
representing the scalar product of ``self`` by ``other``.
|
|
1069
|
+
|
|
1070
|
+
EXAMPLES:
|
|
1071
|
+
|
|
1072
|
+
Scalar product in the Euclidean plane::
|
|
1073
|
+
|
|
1074
|
+
sage: M.<x,y> = EuclideanSpace()
|
|
1075
|
+
sage: u = M.vector_field(x, y, name='u')
|
|
1076
|
+
sage: v = M.vector_field(y, x, name='v')
|
|
1077
|
+
sage: s = u.dot_product(v); s
|
|
1078
|
+
Scalar field u.v on the Euclidean plane E^2
|
|
1079
|
+
sage: s.display()
|
|
1080
|
+
u.v: E^2 → ℝ
|
|
1081
|
+
(x, y) ↦ 2*x*y
|
|
1082
|
+
|
|
1083
|
+
A shortcut alias of ``dot_product`` is ``dot``::
|
|
1084
|
+
|
|
1085
|
+
sage: u.dot(v) == s
|
|
1086
|
+
True
|
|
1087
|
+
|
|
1088
|
+
A test of orthogonality::
|
|
1089
|
+
|
|
1090
|
+
sage: v[:] = -y, x
|
|
1091
|
+
sage: u.dot_product(v) == 0
|
|
1092
|
+
True
|
|
1093
|
+
|
|
1094
|
+
Scalar product with respect to a metric that is not the default one::
|
|
1095
|
+
|
|
1096
|
+
sage: h = M.riemannian_metric('h')
|
|
1097
|
+
sage: h[1,1], h[2,2] = 1/(1+y^2), 1/(1+x^2)
|
|
1098
|
+
sage: s = u.dot_product(v, metric=h); s
|
|
1099
|
+
Scalar field h(u,v) on the Euclidean plane E^2
|
|
1100
|
+
sage: s.display()
|
|
1101
|
+
h(u,v): E^2 → ℝ
|
|
1102
|
+
(x, y) ↦ -(x^3*y - x*y^3)/((x^2 + 1)*y^2 + x^2 + 1)
|
|
1103
|
+
|
|
1104
|
+
Scalar product of two vector fields along a curve (a lemniscate of
|
|
1105
|
+
Gerono)::
|
|
1106
|
+
|
|
1107
|
+
sage: R.<t> = manifolds.RealLine()
|
|
1108
|
+
sage: C = M.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='C')
|
|
1109
|
+
sage: u = C.tangent_vector_field(name='u')
|
|
1110
|
+
sage: u.display()
|
|
1111
|
+
u = cos(t) e_x + (2*cos(t)^2 - 1) e_y
|
|
1112
|
+
sage: I = C.domain(); I
|
|
1113
|
+
Real interval (0, 2*pi)
|
|
1114
|
+
sage: v = I.vector_field(cos(t), -1, dest_map=C, name='v')
|
|
1115
|
+
sage: v.display()
|
|
1116
|
+
v = cos(t) e_x - e_y
|
|
1117
|
+
sage: s = u.dot_product(v); s
|
|
1118
|
+
Scalar field u.v on the Real interval (0, 2*pi)
|
|
1119
|
+
sage: s.display()
|
|
1120
|
+
u.v: (0, 2*pi) → ℝ
|
|
1121
|
+
t ↦ sin(t)^2
|
|
1122
|
+
|
|
1123
|
+
Scalar product between a vector field along the curve and a vector
|
|
1124
|
+
field on the ambient Euclidean plane::
|
|
1125
|
+
|
|
1126
|
+
sage: e_x = M.cartesian_frame()[1]
|
|
1127
|
+
sage: s = u.dot_product(e_x); s
|
|
1128
|
+
Scalar field u.e_x on the Real interval (0, 2*pi)
|
|
1129
|
+
sage: s.display()
|
|
1130
|
+
u.e_x: (0, 2*pi) → ℝ
|
|
1131
|
+
t ↦ cos(t)
|
|
1132
|
+
"""
|
|
1133
|
+
default_metric = metric is None
|
|
1134
|
+
if default_metric:
|
|
1135
|
+
metric = self._ambient_domain.metric()
|
|
1136
|
+
dest_map = self.parent().destination_map()
|
|
1137
|
+
if dest_map != metric.parent().base_module().destination_map():
|
|
1138
|
+
metric = metric.along(dest_map)
|
|
1139
|
+
if dest_map != other.parent().destination_map():
|
|
1140
|
+
other = other.along(dest_map)
|
|
1141
|
+
resu = metric(self, other)
|
|
1142
|
+
# From the above operation the name of resu is "g(u,v')" where
|
|
1143
|
+
# g = metric._name, u = self._name, v = other._name
|
|
1144
|
+
# For a default metric, we change it to "u.v":
|
|
1145
|
+
if (default_metric and self._name is not None and
|
|
1146
|
+
other._name is not None):
|
|
1147
|
+
resu._name = "{}.{}".format(self._name, other._name)
|
|
1148
|
+
resu._latex_name = "{" + self._latex_name + r"}\cdot{" + \
|
|
1149
|
+
other._latex_name + "}"
|
|
1150
|
+
# The name is propagated to possible restrictions of self:
|
|
1151
|
+
for restrict in resu._restrictions.values():
|
|
1152
|
+
restrict.set_name(resu._name, latex_name=resu._latex_name)
|
|
1153
|
+
return resu
|
|
1154
|
+
|
|
1155
|
+
dot = dot_product
|
|
1156
|
+
|
|
1157
|
+
def norm(self, metric=None):
|
|
1158
|
+
r"""
|
|
1159
|
+
Return the norm of ``self`` (with respect to a given metric).
|
|
1160
|
+
|
|
1161
|
+
The *norm* of a vector field `v` with respect to a given
|
|
1162
|
+
pseudo-Riemannian metric `g` is the scalar field `\|v\|` defined by
|
|
1163
|
+
|
|
1164
|
+
.. MATH::
|
|
1165
|
+
|
|
1166
|
+
\|v\| = \sqrt{g(v,v)}
|
|
1167
|
+
|
|
1168
|
+
.. NOTE::
|
|
1169
|
+
|
|
1170
|
+
If the metric `g` is not positive definite, it may be that `\|v\|`
|
|
1171
|
+
takes imaginary values.
|
|
1172
|
+
|
|
1173
|
+
INPUT:
|
|
1174
|
+
|
|
1175
|
+
- ``metric`` -- (default: ``None``) the pseudo-Riemannian metric `g`
|
|
1176
|
+
involved in the definition of the norm; if none is
|
|
1177
|
+
provided, the domain of ``self`` is supposed to be endowed with a
|
|
1178
|
+
default metric (i.e. is supposed to be pseudo-Riemannian manifold,
|
|
1179
|
+
see
|
|
1180
|
+
:class:`~sage.manifolds.differentiable.pseudo_riemannian.PseudoRiemannianManifold`)
|
|
1181
|
+
and the latter is used to define the norm
|
|
1182
|
+
|
|
1183
|
+
OUTPUT:
|
|
1184
|
+
|
|
1185
|
+
- instance of
|
|
1186
|
+
:class:`~sage.manifolds.differentiable.scalarfield.DiffScalarField`
|
|
1187
|
+
representing the norm of ``self``.
|
|
1188
|
+
|
|
1189
|
+
EXAMPLES:
|
|
1190
|
+
|
|
1191
|
+
Norm in the Euclidean plane::
|
|
1192
|
+
|
|
1193
|
+
sage: M.<x,y> = EuclideanSpace()
|
|
1194
|
+
sage: v = M.vector_field(-y, x, name='v')
|
|
1195
|
+
sage: s = v.norm(); s
|
|
1196
|
+
Scalar field |v| on the Euclidean plane E^2
|
|
1197
|
+
sage: s.display()
|
|
1198
|
+
|v|: E^2 → ℝ
|
|
1199
|
+
(x, y) ↦ sqrt(x^2 + y^2)
|
|
1200
|
+
|
|
1201
|
+
The global function :func:`~sage.misc.functional.norm` can be used
|
|
1202
|
+
instead of the method ``norm()``::
|
|
1203
|
+
|
|
1204
|
+
sage: norm(v) == s
|
|
1205
|
+
True
|
|
1206
|
+
|
|
1207
|
+
Norm with respect to a metric that is not the default one::
|
|
1208
|
+
|
|
1209
|
+
sage: h = M.riemannian_metric('h')
|
|
1210
|
+
sage: h[1,1], h[2,2] = 1/(1+y^2), 1/(1+x^2)
|
|
1211
|
+
sage: s = v.norm(metric=h); s
|
|
1212
|
+
Scalar field |v|_h on the Euclidean plane E^2
|
|
1213
|
+
sage: s.display()
|
|
1214
|
+
|v|_h: E^2 → ℝ
|
|
1215
|
+
(x, y) ↦ sqrt((2*x^2 + 1)*y^2 + x^2)/(sqrt(x^2 + 1)*sqrt(y^2 + 1))
|
|
1216
|
+
|
|
1217
|
+
Norm of the tangent vector field to a curve (a lemniscate of Gerono)::
|
|
1218
|
+
|
|
1219
|
+
sage: R.<t> = manifolds.RealLine()
|
|
1220
|
+
sage: C = M.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='C')
|
|
1221
|
+
sage: v = C.tangent_vector_field()
|
|
1222
|
+
sage: v.display()
|
|
1223
|
+
C' = cos(t) e_x + (2*cos(t)^2 - 1) e_y
|
|
1224
|
+
sage: s = v.norm(); s
|
|
1225
|
+
Scalar field |C'| on the Real interval (0, 2*pi)
|
|
1226
|
+
sage: s.display()
|
|
1227
|
+
|C'|: (0, 2*pi) → ℝ
|
|
1228
|
+
t ↦ sqrt(4*cos(t)^4 - 3*cos(t)^2 + 1)
|
|
1229
|
+
"""
|
|
1230
|
+
default_metric = metric is None
|
|
1231
|
+
if default_metric:
|
|
1232
|
+
metric = self._ambient_domain.metric()
|
|
1233
|
+
dest_map = self.parent().destination_map()
|
|
1234
|
+
if dest_map != metric.parent().base_module().destination_map():
|
|
1235
|
+
metric = metric.along(dest_map)
|
|
1236
|
+
resu = metric(self, self).sqrt()
|
|
1237
|
+
if self._name is not None:
|
|
1238
|
+
if default_metric:
|
|
1239
|
+
resu._name = "|{}|".format(self._name)
|
|
1240
|
+
resu._latex_name = r"\left\|" + self._latex_name + \
|
|
1241
|
+
r"\right\|"
|
|
1242
|
+
else:
|
|
1243
|
+
resu._name = "|{}|_{}".format(self._name, metric._name)
|
|
1244
|
+
resu._latex_name = r"\left\|" + self._latex_name + \
|
|
1245
|
+
r"\right\| _{" + metric._latex_name + "}"
|
|
1246
|
+
# The name is propagated to possible restrictions of self:
|
|
1247
|
+
for restrict in resu._restrictions.values():
|
|
1248
|
+
restrict.set_name(resu._name, latex_name=resu._latex_name)
|
|
1249
|
+
return resu
|
|
1250
|
+
|
|
1251
|
+
def cross_product(self, other, metric=None):
|
|
1252
|
+
r"""
|
|
1253
|
+
Return the cross product of ``self`` with another vector field (with
|
|
1254
|
+
respect to a given metric), assuming that the domain of ``self`` is
|
|
1255
|
+
3-dimensional.
|
|
1256
|
+
|
|
1257
|
+
If ``self`` is a vector field `u` on a 3-dimensional differentiable
|
|
1258
|
+
orientable manifold `M` and ``other`` is a vector field `v` on `M`,
|
|
1259
|
+
the *cross product* (also called *vector product*) *of* `u` *by* `v`
|
|
1260
|
+
with respect to a pseudo-Riemannian metric `g` on `M` is the vector
|
|
1261
|
+
field `w = u\times v` defined by
|
|
1262
|
+
|
|
1263
|
+
.. MATH::
|
|
1264
|
+
|
|
1265
|
+
w^i = \epsilon^i_{\phantom{i} jk} u^j v^k
|
|
1266
|
+
= g^{il} \epsilon_{ljk} u^j v^k
|
|
1267
|
+
|
|
1268
|
+
where `\epsilon` is the volume 3-form (Levi-Civita tensor) of `g` (cf.
|
|
1269
|
+
:meth:`~sage.manifolds.differentiable.metric.PseudoRiemannianMetric.volume_form`)
|
|
1270
|
+
|
|
1271
|
+
.. NOTE::
|
|
1272
|
+
|
|
1273
|
+
The method ``cross_product`` is meaningful only if for vector fields on a
|
|
1274
|
+
3-dimensional manifold.
|
|
1275
|
+
|
|
1276
|
+
INPUT:
|
|
1277
|
+
|
|
1278
|
+
- ``other`` -- a vector field, defined on the same domain as ``self``
|
|
1279
|
+
- ``metric`` -- (default: ``None``) the pseudo-Riemannian metric `g`
|
|
1280
|
+
involved in the definition of the cross product; if none is
|
|
1281
|
+
provided, the domain of ``self`` is supposed to be endowed with a
|
|
1282
|
+
default metric (i.e. is supposed to be pseudo-Riemannian manifold,
|
|
1283
|
+
see
|
|
1284
|
+
:class:`~sage.manifolds.differentiable.pseudo_riemannian.PseudoRiemannianManifold`)
|
|
1285
|
+
and the latter is used to define the cross product
|
|
1286
|
+
|
|
1287
|
+
OUTPUT:
|
|
1288
|
+
|
|
1289
|
+
- instance of :class:`VectorField` representing the cross product of
|
|
1290
|
+
``self`` by ``other``.
|
|
1291
|
+
|
|
1292
|
+
EXAMPLES:
|
|
1293
|
+
|
|
1294
|
+
Cross product in the Euclidean 3-space::
|
|
1295
|
+
|
|
1296
|
+
sage: M.<x,y,z> = EuclideanSpace()
|
|
1297
|
+
sage: u = M.vector_field(-y, x, 0, name='u')
|
|
1298
|
+
sage: v = M.vector_field(x, y, 0, name='v')
|
|
1299
|
+
sage: w = u.cross_product(v); w
|
|
1300
|
+
Vector field u x v on the Euclidean space E^3
|
|
1301
|
+
sage: w.display()
|
|
1302
|
+
u x v = (-x^2 - y^2) e_z
|
|
1303
|
+
|
|
1304
|
+
A shortcut alias of ``cross_product`` is ``cross``::
|
|
1305
|
+
|
|
1306
|
+
sage: u.cross(v) == w
|
|
1307
|
+
True
|
|
1308
|
+
|
|
1309
|
+
The cross product of a vector field with itself is zero::
|
|
1310
|
+
|
|
1311
|
+
sage: u.cross_product(u).display()
|
|
1312
|
+
u x u = 0
|
|
1313
|
+
|
|
1314
|
+
Cross product with respect to a metric that is not the default one::
|
|
1315
|
+
|
|
1316
|
+
sage: h = M.riemannian_metric('h')
|
|
1317
|
+
sage: h[1,1], h[2,2], h[3,3] = 1/(1+y^2), 1/(1+z^2), 1/(1+x^2)
|
|
1318
|
+
sage: w = u.cross_product(v, metric=h); w
|
|
1319
|
+
Vector field on the Euclidean space E^3
|
|
1320
|
+
sage: w.display()
|
|
1321
|
+
-(x^2 + y^2)*sqrt(x^2 + 1)/(sqrt(y^2 + 1)*sqrt(z^2 + 1)) e_z
|
|
1322
|
+
|
|
1323
|
+
Cross product of two vector fields along a curve (arc of a helix)::
|
|
1324
|
+
|
|
1325
|
+
sage: R.<t> = manifolds.RealLine()
|
|
1326
|
+
sage: C = M.curve((cos(t), sin(t), t), (t, 0, 2*pi), name='C')
|
|
1327
|
+
sage: u = C.tangent_vector_field()
|
|
1328
|
+
sage: u.display()
|
|
1329
|
+
C' = -sin(t) e_x + cos(t) e_y + e_z
|
|
1330
|
+
sage: I = C.domain(); I
|
|
1331
|
+
Real interval (0, 2*pi)
|
|
1332
|
+
sage: v = I.vector_field(-cos(t), sin(t), 0, dest_map=C)
|
|
1333
|
+
sage: v.display()
|
|
1334
|
+
-cos(t) e_x + sin(t) e_y
|
|
1335
|
+
sage: w = u.cross_product(v); w
|
|
1336
|
+
Vector field along the Real interval (0, 2*pi) with values on the
|
|
1337
|
+
Euclidean space E^3
|
|
1338
|
+
sage: w.parent().destination_map()
|
|
1339
|
+
Curve C in the Euclidean space E^3
|
|
1340
|
+
sage: w.display()
|
|
1341
|
+
-sin(t) e_x - cos(t) e_y + (2*cos(t)^2 - 1) e_z
|
|
1342
|
+
|
|
1343
|
+
Cross product between a vector field along the curve and a vector field
|
|
1344
|
+
on the ambient Euclidean space::
|
|
1345
|
+
|
|
1346
|
+
sage: e_x = M.cartesian_frame()[1]
|
|
1347
|
+
sage: w = u.cross_product(e_x); w
|
|
1348
|
+
Vector field C' x e_x along the Real interval (0, 2*pi) with values
|
|
1349
|
+
on the Euclidean space E^3
|
|
1350
|
+
sage: w.display()
|
|
1351
|
+
C' x e_x = e_y - cos(t) e_z
|
|
1352
|
+
"""
|
|
1353
|
+
if self._ambient_domain.dim() != 3:
|
|
1354
|
+
raise ValueError("the cross product is not defined in dimension " +
|
|
1355
|
+
"different from 3")
|
|
1356
|
+
default_metric = metric is None
|
|
1357
|
+
if default_metric:
|
|
1358
|
+
metric = self._ambient_domain.metric()
|
|
1359
|
+
dest_map = self.parent().destination_map()
|
|
1360
|
+
if dest_map == metric.parent().base_module().destination_map():
|
|
1361
|
+
eps = metric.volume_form(1)
|
|
1362
|
+
else:
|
|
1363
|
+
eps = metric.volume_form(1).along(dest_map)
|
|
1364
|
+
if dest_map != other.parent().destination_map():
|
|
1365
|
+
other = other.along(dest_map)
|
|
1366
|
+
resu = eps.contract(1, 2, self.wedge(other), 0, 1) / 2
|
|
1367
|
+
# The result is named "u x v" only for a default metric:
|
|
1368
|
+
if (default_metric and self._name is not None and
|
|
1369
|
+
other._name is not None):
|
|
1370
|
+
resu._name = "{} x {}".format(self._name, other._name)
|
|
1371
|
+
resu._latex_name = "{" + self._latex_name + r"}\times{" + \
|
|
1372
|
+
other._latex_name + "}"
|
|
1373
|
+
# The name is propagated to possible restrictions of self:
|
|
1374
|
+
for restrict in resu._restrictions.values():
|
|
1375
|
+
restrict.set_name(resu._name, latex_name=resu._latex_name)
|
|
1376
|
+
return resu
|
|
1377
|
+
|
|
1378
|
+
cross = cross_product
|
|
1379
|
+
|
|
1380
|
+
#******************************************************************************
|
|
1381
|
+
|
|
1382
|
+
|
|
1383
|
+
class VectorFieldParal(FiniteRankFreeModuleElement, MultivectorFieldParal,
|
|
1384
|
+
VectorField):
|
|
1385
|
+
r"""
|
|
1386
|
+
Vector field along a differentiable manifold, with values on a
|
|
1387
|
+
parallelizable manifold.
|
|
1388
|
+
|
|
1389
|
+
An instance of this class is a vector field along a differentiable
|
|
1390
|
+
manifold `U` with values on a parallelizable manifold `M`, via a
|
|
1391
|
+
differentiable map `\Phi: U \rightarrow M`. More precisely, given
|
|
1392
|
+
a differentiable map
|
|
1393
|
+
|
|
1394
|
+
.. MATH::
|
|
1395
|
+
|
|
1396
|
+
\Phi:\ U \longrightarrow M,
|
|
1397
|
+
|
|
1398
|
+
a *vector field along* `U` *with values on* `M` is a differentiable map
|
|
1399
|
+
|
|
1400
|
+
.. MATH::
|
|
1401
|
+
|
|
1402
|
+
v:\ U \longrightarrow TM
|
|
1403
|
+
|
|
1404
|
+
(`TM` being the tangent bundle of `M`) such that
|
|
1405
|
+
|
|
1406
|
+
.. MATH::
|
|
1407
|
+
|
|
1408
|
+
\forall p \in U,\ v(p) \in T_{\Phi(p)}M.
|
|
1409
|
+
|
|
1410
|
+
The standard case of vector fields *on* a differentiable manifold
|
|
1411
|
+
corresponds to `U = M` and `\Phi = \mathrm{Id}_M`. Other common cases
|
|
1412
|
+
are `\Phi` being an immersion and `\Phi` being a curve in `M` (`U`
|
|
1413
|
+
is then an open interval of `\RR`).
|
|
1414
|
+
|
|
1415
|
+
.. NOTE::
|
|
1416
|
+
|
|
1417
|
+
If `M` is not parallelizable, then
|
|
1418
|
+
:class:`~sage.manifolds.differentiable.vectorfield.VectorField`
|
|
1419
|
+
*must* be used instead.
|
|
1420
|
+
|
|
1421
|
+
INPUT:
|
|
1422
|
+
|
|
1423
|
+
- ``vector_field_module`` -- free module `\mathfrak{X}(U,\Phi)` of vector
|
|
1424
|
+
fields along `U` with values on `M\supset\Phi(U)`
|
|
1425
|
+
- ``name`` -- (default: ``None``) name given to the vector field
|
|
1426
|
+
- ``latex_name`` -- (default: ``None``) LaTeX symbol to denote the vector
|
|
1427
|
+
field; if none is provided, the LaTeX symbol is set to ``name``
|
|
1428
|
+
|
|
1429
|
+
EXAMPLES:
|
|
1430
|
+
|
|
1431
|
+
A vector field on a parallelizable 3-dimensional manifold::
|
|
1432
|
+
|
|
1433
|
+
sage: M = Manifold(3, 'M')
|
|
1434
|
+
sage: c_xyz.<x,y,z> = M.chart()
|
|
1435
|
+
sage: v = M.vector_field(name='V') ; v
|
|
1436
|
+
Vector field V on the 3-dimensional differentiable manifold M
|
|
1437
|
+
sage: latex(v)
|
|
1438
|
+
V
|
|
1439
|
+
|
|
1440
|
+
Vector fields are considered as elements of a module over the ring
|
|
1441
|
+
(algebra) of scalar fields on `M`::
|
|
1442
|
+
|
|
1443
|
+
sage: v.parent()
|
|
1444
|
+
Free module X(M) of vector fields on the 3-dimensional differentiable
|
|
1445
|
+
manifold M
|
|
1446
|
+
sage: v.parent().base_ring()
|
|
1447
|
+
Algebra of differentiable scalar fields on the 3-dimensional
|
|
1448
|
+
differentiable manifold M
|
|
1449
|
+
sage: v.parent() is M.vector_field_module()
|
|
1450
|
+
True
|
|
1451
|
+
|
|
1452
|
+
A vector field is a tensor field of rank 1 and of type `(1,0)`::
|
|
1453
|
+
|
|
1454
|
+
sage: v.tensor_rank()
|
|
1455
|
+
1
|
|
1456
|
+
sage: v.tensor_type()
|
|
1457
|
+
(1, 0)
|
|
1458
|
+
|
|
1459
|
+
Components of a vector field with respect to a given frame::
|
|
1460
|
+
|
|
1461
|
+
sage: e = M.vector_frame('e') ; M.set_default_frame(e)
|
|
1462
|
+
sage: v[0], v[1], v[2] = (1+y, 4*x*z, 9) # components on M's default frame (e)
|
|
1463
|
+
sage: v.comp()
|
|
1464
|
+
1-index components w.r.t. Vector frame (M, (e_0,e_1,e_2))
|
|
1465
|
+
|
|
1466
|
+
The totality of the components are accessed via the operator ``[:]``::
|
|
1467
|
+
|
|
1468
|
+
sage: v[:] = (1+y, 4*x*z, 9)
|
|
1469
|
+
sage: v[:]
|
|
1470
|
+
[y + 1, 4*x*z, 9]
|
|
1471
|
+
|
|
1472
|
+
The components are also read on the expansion on the frame ``e``,
|
|
1473
|
+
as provided by the method
|
|
1474
|
+
:meth:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor.display`::
|
|
1475
|
+
|
|
1476
|
+
sage: v.display() # expansion in the default frame
|
|
1477
|
+
V = (y + 1) e_0 + 4*x*z e_1 + 9 e_2
|
|
1478
|
+
|
|
1479
|
+
A subset of the components can be accessed by using slice notation::
|
|
1480
|
+
|
|
1481
|
+
sage: v[1:] = (-2, -x*y)
|
|
1482
|
+
sage: v[:]
|
|
1483
|
+
[y + 1, -2, -x*y]
|
|
1484
|
+
sage: v[:2]
|
|
1485
|
+
[y + 1, -2]
|
|
1486
|
+
|
|
1487
|
+
Components in another frame::
|
|
1488
|
+
|
|
1489
|
+
sage: f = M.vector_frame('f')
|
|
1490
|
+
sage: for i in range(3):
|
|
1491
|
+
....: v.set_comp(f)[i] = (i+1)**3 * c_xyz[i]
|
|
1492
|
+
sage: v.comp(f)[2]
|
|
1493
|
+
27*z
|
|
1494
|
+
sage: v[f, 2] # equivalent to above
|
|
1495
|
+
27*z
|
|
1496
|
+
sage: v.display(f)
|
|
1497
|
+
V = x f_0 + 8*y f_1 + 27*z f_2
|
|
1498
|
+
|
|
1499
|
+
One can set the components at the vector definition::
|
|
1500
|
+
|
|
1501
|
+
sage: v = M.vector_field(1+y, 4*x*z, 9, name='V')
|
|
1502
|
+
sage: v.display()
|
|
1503
|
+
V = (y + 1) e_0 + 4*x*z e_1 + 9 e_2
|
|
1504
|
+
|
|
1505
|
+
If the components regard a vector frame different from the default one,
|
|
1506
|
+
the vector frame has to be specified via the argument ``frame``::
|
|
1507
|
+
|
|
1508
|
+
sage: v = M.vector_field(x, 8*y, 27*z, frame=f, name='V')
|
|
1509
|
+
sage: v.display(f)
|
|
1510
|
+
V = x f_0 + 8*y f_1 + 27*z f_2
|
|
1511
|
+
|
|
1512
|
+
For providing the components in various frames, one may use a dictionary::
|
|
1513
|
+
|
|
1514
|
+
sage: v = M.vector_field({e: [1+y, -2, -x*y], f: [x, 8*y, 27*z]},
|
|
1515
|
+
....: name='V')
|
|
1516
|
+
sage: v.display(e)
|
|
1517
|
+
V = (y + 1) e_0 - 2 e_1 - x*y e_2
|
|
1518
|
+
sage: v.display(f)
|
|
1519
|
+
V = x f_0 + 8*y f_1 + 27*z f_2
|
|
1520
|
+
|
|
1521
|
+
It is also possible to construct a vector field from a vector of symbolic
|
|
1522
|
+
expressions (or any other iterable)::
|
|
1523
|
+
|
|
1524
|
+
sage: v = M.vector_field(vector([1+y, 4*x*z, 9]), name='V')
|
|
1525
|
+
sage: v.display()
|
|
1526
|
+
V = (y + 1) e_0 + 4*x*z e_1 + 9 e_2
|
|
1527
|
+
|
|
1528
|
+
The range of the indices depends on the convention set for the manifold::
|
|
1529
|
+
|
|
1530
|
+
sage: M = Manifold(3, 'M', start_index=1)
|
|
1531
|
+
sage: c_xyz.<x,y,z> = M.chart()
|
|
1532
|
+
sage: e = M.vector_frame('e') ; M.set_default_frame(e)
|
|
1533
|
+
sage: v = M.vector_field(1+y, 4*x*z, 9, name='V')
|
|
1534
|
+
sage: v[0]
|
|
1535
|
+
Traceback (most recent call last):
|
|
1536
|
+
...
|
|
1537
|
+
IndexError: index out of range: 0 not in [1, 3]
|
|
1538
|
+
sage: v[1] # OK
|
|
1539
|
+
y + 1
|
|
1540
|
+
|
|
1541
|
+
A vector field acts on scalar fields (derivation along the vector field)::
|
|
1542
|
+
|
|
1543
|
+
sage: M = Manifold(2, 'M')
|
|
1544
|
+
sage: c_cart.<x,y> = M.chart()
|
|
1545
|
+
sage: f = M.scalar_field(x*y^2, name='f')
|
|
1546
|
+
sage: v = M.vector_field(-y, x, name='v')
|
|
1547
|
+
sage: v.display()
|
|
1548
|
+
v = -y ∂/∂x + x ∂/∂y
|
|
1549
|
+
sage: v(f)
|
|
1550
|
+
Scalar field v(f) on the 2-dimensional differentiable manifold M
|
|
1551
|
+
sage: v(f).expr()
|
|
1552
|
+
2*x^2*y - y^3
|
|
1553
|
+
sage: latex(v(f))
|
|
1554
|
+
v\left(f\right)
|
|
1555
|
+
|
|
1556
|
+
Example of a vector field associated with a non-trivial map `\Phi`;
|
|
1557
|
+
a vector field along a curve in `M`::
|
|
1558
|
+
|
|
1559
|
+
sage: R = Manifold(1, 'R')
|
|
1560
|
+
sage: T.<t> = R.chart() # canonical chart on R
|
|
1561
|
+
sage: Phi = R.diff_map(M, [cos(t), sin(t)], name='Phi') ; Phi
|
|
1562
|
+
Differentiable map Phi from the 1-dimensional differentiable manifold R
|
|
1563
|
+
to the 2-dimensional differentiable manifold M
|
|
1564
|
+
sage: Phi.display()
|
|
1565
|
+
Phi: R → M
|
|
1566
|
+
t ↦ (x, y) = (cos(t), sin(t))
|
|
1567
|
+
sage: w = R.vector_field(-sin(t), cos(t), dest_map=Phi, name='w') ; w
|
|
1568
|
+
Vector field w along the 1-dimensional differentiable manifold R with
|
|
1569
|
+
values on the 2-dimensional differentiable manifold M
|
|
1570
|
+
sage: w.parent()
|
|
1571
|
+
Free module X(R,Phi) of vector fields along the 1-dimensional
|
|
1572
|
+
differentiable manifold R mapped into the 2-dimensional differentiable
|
|
1573
|
+
manifold M
|
|
1574
|
+
sage: w.display()
|
|
1575
|
+
w = -sin(t) ∂/∂x + cos(t) ∂/∂y
|
|
1576
|
+
|
|
1577
|
+
Value at a given point::
|
|
1578
|
+
|
|
1579
|
+
sage: p = R((0,), name='p') ; p
|
|
1580
|
+
Point p on the 1-dimensional differentiable manifold R
|
|
1581
|
+
sage: w.at(p)
|
|
1582
|
+
Tangent vector w at Point Phi(p) on the 2-dimensional differentiable
|
|
1583
|
+
manifold M
|
|
1584
|
+
sage: w.at(p).display()
|
|
1585
|
+
w = ∂/∂y
|
|
1586
|
+
sage: w.at(p) == v.at(Phi(p))
|
|
1587
|
+
True
|
|
1588
|
+
"""
|
|
1589
|
+
def __init__(self, vector_field_module, name=None, latex_name=None):
|
|
1590
|
+
r"""
|
|
1591
|
+
Construct a vector field with values on a parallelizable manifold.
|
|
1592
|
+
|
|
1593
|
+
TESTS:
|
|
1594
|
+
|
|
1595
|
+
Construction via ``parent.element_class``, and not via a direct call
|
|
1596
|
+
to ``VectorFieldParal``, to fit with the category framework::
|
|
1597
|
+
|
|
1598
|
+
sage: M = Manifold(2, 'M')
|
|
1599
|
+
sage: X.<x,y> = M.chart() # makes M parallelizable
|
|
1600
|
+
sage: XM = M.vector_field_module() # the parent
|
|
1601
|
+
sage: v = XM.element_class(XM, name='v'); v
|
|
1602
|
+
Vector field v on the 2-dimensional differentiable manifold M
|
|
1603
|
+
sage: v[:] = (-y, x)
|
|
1604
|
+
sage: v.display()
|
|
1605
|
+
v = -y ∂/∂x + x ∂/∂y
|
|
1606
|
+
sage: TestSuite(v).run()
|
|
1607
|
+
|
|
1608
|
+
Construction via ``DifferentiableManifold.vector_field``::
|
|
1609
|
+
|
|
1610
|
+
sage: u = M.vector_field(1+x, 1-y, name='u'); u
|
|
1611
|
+
Vector field u on the 2-dimensional differentiable manifold M
|
|
1612
|
+
sage: type(u) == type(v)
|
|
1613
|
+
True
|
|
1614
|
+
sage: u.parent() is v.parent()
|
|
1615
|
+
True
|
|
1616
|
+
sage: TestSuite(u).run()
|
|
1617
|
+
"""
|
|
1618
|
+
FiniteRankFreeModuleElement.__init__(self, vector_field_module,
|
|
1619
|
+
name=name, latex_name=latex_name)
|
|
1620
|
+
# MultivectorFieldParal attributes:
|
|
1621
|
+
self._domain = vector_field_module._domain
|
|
1622
|
+
self._ambient_domain = vector_field_module._ambient_domain
|
|
1623
|
+
# VectorField attributes:
|
|
1624
|
+
self._vmodule = vector_field_module
|
|
1625
|
+
# Initialization of derived quantities:
|
|
1626
|
+
MultivectorFieldParal._init_derived(self)
|
|
1627
|
+
VectorField._init_derived(self)
|
|
1628
|
+
# Initialization of list of quantities depending on self:
|
|
1629
|
+
self._init_dependencies()
|
|
1630
|
+
|
|
1631
|
+
def _repr_(self) :
|
|
1632
|
+
r"""
|
|
1633
|
+
String representation of ``self``.
|
|
1634
|
+
|
|
1635
|
+
TESTS::
|
|
1636
|
+
|
|
1637
|
+
sage: M = Manifold(2, 'M')
|
|
1638
|
+
sage: X.<x,y> = M.chart() # makes M parallelizable
|
|
1639
|
+
sage: v = M.vector_field(name='v')
|
|
1640
|
+
sage: v._repr_()
|
|
1641
|
+
'Vector field v on the 2-dimensional differentiable manifold M'
|
|
1642
|
+
sage: repr(v) # indirect doctest
|
|
1643
|
+
'Vector field v on the 2-dimensional differentiable manifold M'
|
|
1644
|
+
sage: v # indirect doctest
|
|
1645
|
+
Vector field v on the 2-dimensional differentiable manifold M
|
|
1646
|
+
"""
|
|
1647
|
+
return VectorField._repr_(self)
|
|
1648
|
+
|
|
1649
|
+
def _new_instance(self):
|
|
1650
|
+
r"""
|
|
1651
|
+
Create an instance of the same class as ``self`` on the same module.
|
|
1652
|
+
|
|
1653
|
+
TESTS::
|
|
1654
|
+
|
|
1655
|
+
sage: M = Manifold(2, 'M')
|
|
1656
|
+
sage: X.<x,y> = M.chart() # makes M parallelizable
|
|
1657
|
+
sage: v = M.vector_field(name='v')
|
|
1658
|
+
sage: u = v._new_instance(); u
|
|
1659
|
+
Vector field on the 2-dimensional differentiable manifold M
|
|
1660
|
+
sage: u.parent() is v.parent()
|
|
1661
|
+
True
|
|
1662
|
+
"""
|
|
1663
|
+
return type(self)(self._fmodule)
|
|
1664
|
+
|
|
1665
|
+
def _del_derived(self, del_restrictions=True):
|
|
1666
|
+
r"""
|
|
1667
|
+
Delete the derived quantities.
|
|
1668
|
+
|
|
1669
|
+
INPUT:
|
|
1670
|
+
|
|
1671
|
+
- ``del_restrictions`` -- boolean (default: ``True``); determines whether
|
|
1672
|
+
the restrictions of ``self`` to subdomains are deleted
|
|
1673
|
+
|
|
1674
|
+
TESTS::
|
|
1675
|
+
|
|
1676
|
+
sage: M = Manifold(2, 'M')
|
|
1677
|
+
sage: X.<x,y> = M.chart() # makes M parallelizable
|
|
1678
|
+
sage: v = M.vector_field(name='v')
|
|
1679
|
+
sage: v._del_derived()
|
|
1680
|
+
"""
|
|
1681
|
+
MultivectorFieldParal._del_derived(self,
|
|
1682
|
+
del_restrictions=del_restrictions)
|
|
1683
|
+
VectorField._del_derived(self)
|
|
1684
|
+
self._del_dependencies()
|
|
1685
|
+
|
|
1686
|
+
def __call__(self, scalar):
|
|
1687
|
+
r"""
|
|
1688
|
+
Action on a scalar field.
|
|
1689
|
+
|
|
1690
|
+
INPUT:
|
|
1691
|
+
|
|
1692
|
+
- ``scalar`` -- scalar field `f`
|
|
1693
|
+
|
|
1694
|
+
OUTPUT:
|
|
1695
|
+
|
|
1696
|
+
- scalar field representing the derivative of `f` along the vector
|
|
1697
|
+
field, i.e. `v^i \frac{\partial f}{\partial x^i}`
|
|
1698
|
+
|
|
1699
|
+
EXAMPLES:
|
|
1700
|
+
|
|
1701
|
+
Action of a vector field on a scalar field on a 2-dimensional
|
|
1702
|
+
manifold::
|
|
1703
|
+
|
|
1704
|
+
sage: M = Manifold(2, 'M')
|
|
1705
|
+
sage: c_cart.<x,y> = M.chart()
|
|
1706
|
+
sage: f = M.scalar_field(x*y^2)
|
|
1707
|
+
sage: v = M.vector_field(-y, x)
|
|
1708
|
+
sage: v(f)
|
|
1709
|
+
Scalar field on the 2-dimensional differentiable manifold M
|
|
1710
|
+
sage: v(f).display()
|
|
1711
|
+
M → ℝ
|
|
1712
|
+
(x, y) ↦ 2*x^2*y - y^3
|
|
1713
|
+
"""
|
|
1714
|
+
# This method enforces VectorField.__call__
|
|
1715
|
+
# instead of FiniteRankFreeModuleElement.__call__, which would have
|
|
1716
|
+
# been inheritated otherwise
|
|
1717
|
+
return VectorField.__call__(self, scalar)
|