passagemath-symbolics 10.6.40__cp314-cp314t-macosx_13_0_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.
Potentially problematic release.
This version of passagemath-symbolics might be problematic. Click here for more details.
- passagemath_symbolics/.dylibs/libgmp.10.dylib +0 -0
- passagemath_symbolics/__init__.py +3 -0
- passagemath_symbolics-10.6.40.dist-info/METADATA +187 -0
- passagemath_symbolics-10.6.40.dist-info/RECORD +172 -0
- passagemath_symbolics-10.6.40.dist-info/WHEEL +6 -0
- passagemath_symbolics-10.6.40.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-314t-darwin.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-314t-darwin.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-314t-darwin.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-314t-darwin.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-314t-darwin.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,2517 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-symbolics
|
|
2
|
+
r"""
|
|
3
|
+
Euclidean Spaces
|
|
4
|
+
|
|
5
|
+
A *Euclidean space of dimension* `n` is an affine space `E`, whose associated
|
|
6
|
+
vector space is a `n`-dimensional vector space over `\RR` and is equipped with
|
|
7
|
+
a positive definite symmetric bilinear form, called the *scalar product* or
|
|
8
|
+
*dot product* [Ber1987]_. A Euclidean space of dimension `n` can also be
|
|
9
|
+
viewed as a Riemannian manifold that is diffeomorphic to `\RR^n` and that
|
|
10
|
+
has a flat metric `g`. The Euclidean scalar product is then that defined
|
|
11
|
+
by the Riemannian metric `g`.
|
|
12
|
+
|
|
13
|
+
The current implementation of Euclidean spaces is based on the second point of
|
|
14
|
+
view. This allows for the introduction of various coordinate systems in
|
|
15
|
+
addition to the usual the Cartesian systems. Standard curvilinear systems
|
|
16
|
+
(planar, spherical and cylindrical coordinates) are predefined for
|
|
17
|
+
2-dimensional and 3-dimensional Euclidean spaces, along with the corresponding
|
|
18
|
+
transition maps between them. Another benefit of such an implementation is
|
|
19
|
+
the direct use of methods for vector calculus already implemented at the
|
|
20
|
+
level of Riemannian manifolds (see, e.g., the methods
|
|
21
|
+
:meth:`~sage.manifolds.differentiable.vectorfield.VectorField.cross_product`
|
|
22
|
+
and
|
|
23
|
+
:meth:`~sage.manifolds.differentiable.vectorfield.VectorField.curl`,
|
|
24
|
+
as well as the module :mod:`~sage.manifolds.operators`).
|
|
25
|
+
|
|
26
|
+
Euclidean spaces are implemented via the following classes:
|
|
27
|
+
|
|
28
|
+
- :class:`EuclideanSpace` for generic values `n`,
|
|
29
|
+
- :class:`EuclideanPlane` for `n = 2`,
|
|
30
|
+
- :class:`Euclidean3dimSpace` for `n = 3`.
|
|
31
|
+
|
|
32
|
+
The user interface is provided by :class:`EuclideanSpace`.
|
|
33
|
+
|
|
34
|
+
.. _EuclideanSpace_example1:
|
|
35
|
+
|
|
36
|
+
.. RUBRIC:: Example 1: the Euclidean plane
|
|
37
|
+
|
|
38
|
+
We start by declaring the Euclidean plane ``E``, with ``(x, y)`` as
|
|
39
|
+
Cartesian coordinates::
|
|
40
|
+
|
|
41
|
+
sage: E.<x,y> = EuclideanSpace()
|
|
42
|
+
sage: E
|
|
43
|
+
Euclidean plane E^2
|
|
44
|
+
sage: dim(E)
|
|
45
|
+
2
|
|
46
|
+
|
|
47
|
+
``E`` is automatically endowed with the chart of Cartesian coordinates::
|
|
48
|
+
|
|
49
|
+
sage: E.atlas()
|
|
50
|
+
[Chart (E^2, (x, y))]
|
|
51
|
+
sage: cartesian = E.default_chart(); cartesian
|
|
52
|
+
Chart (E^2, (x, y))
|
|
53
|
+
|
|
54
|
+
Thanks to the use of ``<x,y>`` when declaring ``E``, the coordinates `(x,y)`
|
|
55
|
+
have been injected in the global namespace, i.e. the Python variables ``x``
|
|
56
|
+
and ``y`` have been created and are available to form symbolic expressions::
|
|
57
|
+
|
|
58
|
+
sage: y
|
|
59
|
+
y
|
|
60
|
+
sage: type(y)
|
|
61
|
+
<class 'sage.symbolic.expression.Expression'>
|
|
62
|
+
sage: assumptions()
|
|
63
|
+
[x is real, y is real]
|
|
64
|
+
|
|
65
|
+
The metric tensor of ``E`` is predefined::
|
|
66
|
+
|
|
67
|
+
sage: g = E.metric(); g
|
|
68
|
+
Riemannian metric g on the Euclidean plane E^2
|
|
69
|
+
sage: g.display()
|
|
70
|
+
g = dx⊗dx + dy⊗dy
|
|
71
|
+
sage: g[:]
|
|
72
|
+
[1 0]
|
|
73
|
+
[0 1]
|
|
74
|
+
|
|
75
|
+
It is a *flat* metric, i.e. it has a vanishing Riemann tensor::
|
|
76
|
+
|
|
77
|
+
sage: g.riemann()
|
|
78
|
+
Tensor field Riem(g) of type (1,3) on the Euclidean plane E^2
|
|
79
|
+
sage: g.riemann().display()
|
|
80
|
+
Riem(g) = 0
|
|
81
|
+
|
|
82
|
+
Polar coordinates `(r,\phi)` are introduced by::
|
|
83
|
+
|
|
84
|
+
sage: polar.<r,ph> = E.polar_coordinates()
|
|
85
|
+
sage: polar
|
|
86
|
+
Chart (E^2, (r, ph))
|
|
87
|
+
|
|
88
|
+
``E`` is now endowed with two coordinate charts::
|
|
89
|
+
|
|
90
|
+
sage: E.atlas()
|
|
91
|
+
[Chart (E^2, (x, y)), Chart (E^2, (r, ph))]
|
|
92
|
+
|
|
93
|
+
The ranges of the coordinates introduced so far are::
|
|
94
|
+
|
|
95
|
+
sage: cartesian.coord_range()
|
|
96
|
+
x: (-oo, +oo); y: (-oo, +oo)
|
|
97
|
+
sage: polar.coord_range()
|
|
98
|
+
r: (0, +oo); ph: [0, 2*pi] (periodic)
|
|
99
|
+
|
|
100
|
+
The transition map from polar coordinates to Cartesian ones is::
|
|
101
|
+
|
|
102
|
+
sage: E.coord_change(polar, cartesian).display()
|
|
103
|
+
x = r*cos(ph)
|
|
104
|
+
y = r*sin(ph)
|
|
105
|
+
|
|
106
|
+
while the reverse one is::
|
|
107
|
+
|
|
108
|
+
sage: E.coord_change(cartesian, polar).display()
|
|
109
|
+
r = sqrt(x^2 + y^2)
|
|
110
|
+
ph = arctan2(y, x)
|
|
111
|
+
|
|
112
|
+
A point of ``E`` is constructed from its coordinates (by default in the
|
|
113
|
+
Cartesian chart)::
|
|
114
|
+
|
|
115
|
+
sage: p = E((-1,1), name='p'); p
|
|
116
|
+
Point p on the Euclidean plane E^2
|
|
117
|
+
sage: p.parent()
|
|
118
|
+
Euclidean plane E^2
|
|
119
|
+
|
|
120
|
+
The coordinates of a point are obtained by letting the corresponding chart
|
|
121
|
+
act on it::
|
|
122
|
+
|
|
123
|
+
sage: cartesian(p)
|
|
124
|
+
(-1, 1)
|
|
125
|
+
sage: polar(p)
|
|
126
|
+
(sqrt(2), 3/4*pi)
|
|
127
|
+
|
|
128
|
+
At this stage, ``E`` is endowed with three vector frames::
|
|
129
|
+
|
|
130
|
+
sage: E.frames()
|
|
131
|
+
[Coordinate frame (E^2, (e_x,e_y)),
|
|
132
|
+
Coordinate frame (E^2, (∂/∂r,∂/∂ph)),
|
|
133
|
+
Vector frame (E^2, (e_r,e_ph))]
|
|
134
|
+
|
|
135
|
+
The third one is the standard orthonormal frame associated with polar
|
|
136
|
+
coordinates, as we can check from the metric components in it::
|
|
137
|
+
|
|
138
|
+
sage: polar_frame = E.polar_frame(); polar_frame
|
|
139
|
+
Vector frame (E^2, (e_r,e_ph))
|
|
140
|
+
sage: g[polar_frame,:]
|
|
141
|
+
[1 0]
|
|
142
|
+
[0 1]
|
|
143
|
+
|
|
144
|
+
The expression of the metric tensor in terms of polar coordinates is::
|
|
145
|
+
|
|
146
|
+
sage: g.display(polar)
|
|
147
|
+
g = dr⊗dr + r^2 dph⊗dph
|
|
148
|
+
|
|
149
|
+
A vector field on ``E``::
|
|
150
|
+
|
|
151
|
+
sage: v = E.vector_field(-y, x, name='v'); v
|
|
152
|
+
Vector field v on the Euclidean plane E^2
|
|
153
|
+
sage: v.display()
|
|
154
|
+
v = -y e_x + x e_y
|
|
155
|
+
sage: v[:]
|
|
156
|
+
[-y, x]
|
|
157
|
+
|
|
158
|
+
By default, the components of ``v``, as returned by ``display`` or the bracket
|
|
159
|
+
operator, refer to the Cartesian frame on ``E``; to get the components with
|
|
160
|
+
respect to the orthonormal polar frame, one has to specify it explicitly,
|
|
161
|
+
generally along with the polar chart for the coordinate expression of the
|
|
162
|
+
components::
|
|
163
|
+
|
|
164
|
+
sage: v.display(polar_frame, polar)
|
|
165
|
+
v = r e_ph
|
|
166
|
+
sage: v[polar_frame,:,polar]
|
|
167
|
+
[0, r]
|
|
168
|
+
|
|
169
|
+
Note that the default frame for the display of vector fields can be changed
|
|
170
|
+
thanks to the method
|
|
171
|
+
:meth:`~sage.manifolds.differentiable.manifold.DifferentiableManifold.set_default_frame`;
|
|
172
|
+
in the same vein, the default coordinates can be changed via the method
|
|
173
|
+
:meth:`~sage.manifolds.manifold.TopologicalManifold.set_default_chart`::
|
|
174
|
+
|
|
175
|
+
sage: E.set_default_frame(polar_frame)
|
|
176
|
+
sage: E.set_default_chart(polar)
|
|
177
|
+
sage: v.display()
|
|
178
|
+
v = r e_ph
|
|
179
|
+
sage: v[:]
|
|
180
|
+
[0, r]
|
|
181
|
+
sage: E.set_default_frame(E.cartesian_frame()) # revert to Cartesian frame
|
|
182
|
+
sage: E.set_default_chart(cartesian) # and chart
|
|
183
|
+
|
|
184
|
+
When defining a vector field from components relative to a vector frame
|
|
185
|
+
different from the default one, the vector frame has to be specified
|
|
186
|
+
explicitly::
|
|
187
|
+
|
|
188
|
+
sage: v = E.vector_field(1, 0, frame=polar_frame)
|
|
189
|
+
sage: v.display(polar_frame)
|
|
190
|
+
e_r
|
|
191
|
+
sage: v.display()
|
|
192
|
+
x/sqrt(x^2 + y^2) e_x + y/sqrt(x^2 + y^2) e_y
|
|
193
|
+
|
|
194
|
+
The argument ``chart`` must be used to specify in which coordinate
|
|
195
|
+
chart the components are expressed::
|
|
196
|
+
|
|
197
|
+
sage: v = E.vector_field(0, r, frame=polar_frame, chart=polar)
|
|
198
|
+
sage: v.display(polar_frame, polar)
|
|
199
|
+
r e_ph
|
|
200
|
+
sage: v.display()
|
|
201
|
+
-y e_x + x e_y
|
|
202
|
+
|
|
203
|
+
It is also possible to pass the components as a dictionary, with
|
|
204
|
+
a pair (vector frame, chart) as a key::
|
|
205
|
+
|
|
206
|
+
sage: v = E.vector_field({(polar_frame, polar): (0, r)})
|
|
207
|
+
sage: v.display(polar_frame, polar)
|
|
208
|
+
r e_ph
|
|
209
|
+
|
|
210
|
+
The key can be reduced to the vector frame if the chart is the default
|
|
211
|
+
one::
|
|
212
|
+
|
|
213
|
+
sage: v = E.vector_field({polar_frame: (0, 1)})
|
|
214
|
+
sage: v.display(polar_frame)
|
|
215
|
+
e_ph
|
|
216
|
+
|
|
217
|
+
Finally, it is possible to construct the vector field without
|
|
218
|
+
initializing any component::
|
|
219
|
+
|
|
220
|
+
sage: v = E.vector_field(); v
|
|
221
|
+
Vector field on the Euclidean plane E^2
|
|
222
|
+
|
|
223
|
+
The components can then by set in a second stage, via the square
|
|
224
|
+
bracket operator, the unset components being assumed to be zero::
|
|
225
|
+
|
|
226
|
+
sage: v[1] = -y
|
|
227
|
+
sage: v.display() # v[2] is zero
|
|
228
|
+
-y e_x
|
|
229
|
+
sage: v[2] = x
|
|
230
|
+
sage: v.display()
|
|
231
|
+
-y e_x + x e_y
|
|
232
|
+
|
|
233
|
+
The above is equivalent to::
|
|
234
|
+
|
|
235
|
+
sage: v[:] = -y, x
|
|
236
|
+
sage: v.display()
|
|
237
|
+
-y e_x + x e_y
|
|
238
|
+
|
|
239
|
+
The square bracket operator can also be used to set components in a
|
|
240
|
+
vector frame that is not the default one::
|
|
241
|
+
|
|
242
|
+
sage: v = E.vector_field(name='v')
|
|
243
|
+
sage: v[polar_frame, 2, polar] = r
|
|
244
|
+
sage: v.display(polar_frame, polar)
|
|
245
|
+
v = r e_ph
|
|
246
|
+
sage: v.display()
|
|
247
|
+
v = -y e_x + x e_y
|
|
248
|
+
|
|
249
|
+
The value of the vector field ``v`` at point ``p``::
|
|
250
|
+
|
|
251
|
+
sage: vp = v.at(p); vp
|
|
252
|
+
Vector v at Point p on the Euclidean plane E^2
|
|
253
|
+
sage: vp.display()
|
|
254
|
+
v = -e_x - e_y
|
|
255
|
+
sage: vp.display(polar_frame.at(p))
|
|
256
|
+
v = sqrt(2) e_ph
|
|
257
|
+
|
|
258
|
+
A scalar field on ``E``::
|
|
259
|
+
|
|
260
|
+
sage: f = E.scalar_field(x*y, name='f'); f
|
|
261
|
+
Scalar field f on the Euclidean plane E^2
|
|
262
|
+
sage: f.display()
|
|
263
|
+
f: E^2 → ℝ
|
|
264
|
+
(x, y) ↦ x*y
|
|
265
|
+
(r, ph) ↦ r^2*cos(ph)*sin(ph)
|
|
266
|
+
|
|
267
|
+
The value of ``f`` at point ``p``::
|
|
268
|
+
|
|
269
|
+
sage: f(p)
|
|
270
|
+
-1
|
|
271
|
+
|
|
272
|
+
The gradient of ``f``::
|
|
273
|
+
|
|
274
|
+
sage: from sage.manifolds.operators import * # to get grad, div, etc.
|
|
275
|
+
sage: w = grad(f); w
|
|
276
|
+
Vector field grad(f) on the Euclidean plane E^2
|
|
277
|
+
sage: w.display()
|
|
278
|
+
grad(f) = y e_x + x e_y
|
|
279
|
+
sage: w.display(polar_frame, polar)
|
|
280
|
+
grad(f) = 2*r*cos(ph)*sin(ph) e_r + (2*cos(ph)^2 - 1)*r e_ph
|
|
281
|
+
|
|
282
|
+
The dot product of two vector fields::
|
|
283
|
+
|
|
284
|
+
sage: s = v.dot(w); s
|
|
285
|
+
Scalar field v.grad(f) on the Euclidean plane E^2
|
|
286
|
+
sage: s.display()
|
|
287
|
+
v.grad(f): E^2 → ℝ
|
|
288
|
+
(x, y) ↦ x^2 - y^2
|
|
289
|
+
(r, ph) ↦ (2*cos(ph)^2 - 1)*r^2
|
|
290
|
+
sage: s.expr()
|
|
291
|
+
x^2 - y^2
|
|
292
|
+
|
|
293
|
+
The norm is related to the dot product by the standard formula::
|
|
294
|
+
|
|
295
|
+
sage: norm(v)^2 == v.dot(v)
|
|
296
|
+
True
|
|
297
|
+
|
|
298
|
+
The divergence of the vector field ``v``::
|
|
299
|
+
|
|
300
|
+
sage: s = div(v); s
|
|
301
|
+
Scalar field div(v) on the Euclidean plane E^2
|
|
302
|
+
sage: s.display()
|
|
303
|
+
div(v): E^2 → ℝ
|
|
304
|
+
(x, y) ↦ 0
|
|
305
|
+
(r, ph) ↦ 0
|
|
306
|
+
|
|
307
|
+
.. _EuclideanSpace_example2:
|
|
308
|
+
|
|
309
|
+
.. RUBRIC:: Example 2: Vector calculus in the Euclidean 3-space
|
|
310
|
+
|
|
311
|
+
We start by declaring the 3-dimensional Euclidean space ``E``, with
|
|
312
|
+
``(x,y,z)`` as Cartesian coordinates::
|
|
313
|
+
|
|
314
|
+
sage: E.<x,y,z> = EuclideanSpace()
|
|
315
|
+
sage: E
|
|
316
|
+
Euclidean space E^3
|
|
317
|
+
|
|
318
|
+
A simple vector field on ``E``::
|
|
319
|
+
|
|
320
|
+
sage: v = E.vector_field(-y, x, 0, name='v')
|
|
321
|
+
sage: v.display()
|
|
322
|
+
v = -y e_x + x e_y
|
|
323
|
+
sage: v[:]
|
|
324
|
+
[-y, x, 0]
|
|
325
|
+
|
|
326
|
+
The Euclidean norm of ``v``::
|
|
327
|
+
|
|
328
|
+
sage: s = norm(v); s
|
|
329
|
+
Scalar field |v| on the Euclidean space E^3
|
|
330
|
+
sage: s.display()
|
|
331
|
+
|v|: E^3 → ℝ
|
|
332
|
+
(x, y, z) ↦ sqrt(x^2 + y^2)
|
|
333
|
+
sage: s.expr()
|
|
334
|
+
sqrt(x^2 + y^2)
|
|
335
|
+
|
|
336
|
+
The divergence of ``v`` is zero::
|
|
337
|
+
|
|
338
|
+
sage: from sage.manifolds.operators import *
|
|
339
|
+
sage: div(v)
|
|
340
|
+
Scalar field div(v) on the Euclidean space E^3
|
|
341
|
+
sage: div(v).display()
|
|
342
|
+
div(v): E^3 → ℝ
|
|
343
|
+
(x, y, z) ↦ 0
|
|
344
|
+
|
|
345
|
+
while its curl is a constant vector field along `e_z`::
|
|
346
|
+
|
|
347
|
+
sage: w = curl(v); w
|
|
348
|
+
Vector field curl(v) on the Euclidean space E^3
|
|
349
|
+
sage: w.display()
|
|
350
|
+
curl(v) = 2 e_z
|
|
351
|
+
|
|
352
|
+
The gradient of a scalar field::
|
|
353
|
+
|
|
354
|
+
sage: f = E.scalar_field(sin(x*y*z), name='f')
|
|
355
|
+
sage: u = grad(f); u
|
|
356
|
+
Vector field grad(f) on the Euclidean space E^3
|
|
357
|
+
sage: u.display()
|
|
358
|
+
grad(f) = y*z*cos(x*y*z) e_x + x*z*cos(x*y*z) e_y + x*y*cos(x*y*z) e_z
|
|
359
|
+
|
|
360
|
+
The curl of a gradient is zero::
|
|
361
|
+
|
|
362
|
+
sage: curl(u).display()
|
|
363
|
+
curl(grad(f)) = 0
|
|
364
|
+
|
|
365
|
+
The dot product of two vector fields::
|
|
366
|
+
|
|
367
|
+
sage: s = u.dot(v); s
|
|
368
|
+
Scalar field grad(f).v on the Euclidean space E^3
|
|
369
|
+
sage: s.expr()
|
|
370
|
+
(x^2 - y^2)*z*cos(x*y*z)
|
|
371
|
+
|
|
372
|
+
The cross product of two vector fields::
|
|
373
|
+
|
|
374
|
+
sage: a = u.cross(v); a
|
|
375
|
+
Vector field grad(f) x v on the Euclidean space E^3
|
|
376
|
+
sage: a.display()
|
|
377
|
+
grad(f) x v = -x^2*y*cos(x*y*z) e_x - x*y^2*cos(x*y*z) e_y
|
|
378
|
+
+ 2*x*y*z*cos(x*y*z) e_z
|
|
379
|
+
|
|
380
|
+
The scalar triple product of three vector fields::
|
|
381
|
+
|
|
382
|
+
sage: triple_product = E.scalar_triple_product()
|
|
383
|
+
sage: s = triple_product(u, v, w); s
|
|
384
|
+
Scalar field epsilon(grad(f),v,curl(v)) on the Euclidean space E^3
|
|
385
|
+
sage: s.expr()
|
|
386
|
+
4*x*y*z*cos(x*y*z)
|
|
387
|
+
|
|
388
|
+
Let us check that the scalar triple product of `u`, `v` and `w` is
|
|
389
|
+
`u\cdot(v\times w)`::
|
|
390
|
+
|
|
391
|
+
sage: s == u.dot(v.cross(w))
|
|
392
|
+
True
|
|
393
|
+
|
|
394
|
+
AUTHORS:
|
|
395
|
+
|
|
396
|
+
- Eric Gourgoulhon (2018): initial version
|
|
397
|
+
|
|
398
|
+
REFERENCES:
|
|
399
|
+
|
|
400
|
+
- \M. Berger: *Geometry I* [Ber1987]_
|
|
401
|
+
"""
|
|
402
|
+
|
|
403
|
+
#*****************************************************************************
|
|
404
|
+
# Copyright (C) 2018 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
|
|
405
|
+
#
|
|
406
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
|
407
|
+
# as published by the Free Software Foundation; either version 2 of
|
|
408
|
+
# the License, or (at your option) any later version.
|
|
409
|
+
# https://www.gnu.org/licenses/
|
|
410
|
+
#*****************************************************************************
|
|
411
|
+
|
|
412
|
+
from sage.categories.manifolds import Manifolds
|
|
413
|
+
from sage.categories.metric_spaces import MetricSpaces
|
|
414
|
+
from sage.functions.trig import atan2, cos, sin
|
|
415
|
+
from sage.manifolds.differentiable.pseudo_riemannian import PseudoRiemannianManifold
|
|
416
|
+
from sage.misc.functional import sqrt
|
|
417
|
+
from sage.misc.latex import latex
|
|
418
|
+
from sage.rings.real_mpfr import RR
|
|
419
|
+
|
|
420
|
+
###############################################################################
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
class EuclideanSpace(PseudoRiemannianManifold):
|
|
424
|
+
r"""
|
|
425
|
+
Euclidean space.
|
|
426
|
+
|
|
427
|
+
A *Euclidean space of dimension* `n` is an affine space `E`, whose
|
|
428
|
+
associated vector space is a `n`-dimensional vector space over `\RR` and
|
|
429
|
+
is equipped with a positive definite symmetric bilinear form, called
|
|
430
|
+
the *scalar product* or *dot product*.
|
|
431
|
+
|
|
432
|
+
Euclidean space of dimension `n` can be viewed as a Riemannian manifold
|
|
433
|
+
that is diffeomorphic to `\RR^n` and that has a flat metric `g`. The
|
|
434
|
+
Euclidean scalar product is the one defined by the Riemannian metric `g`.
|
|
435
|
+
|
|
436
|
+
INPUT:
|
|
437
|
+
|
|
438
|
+
- ``n`` -- positive integer; dimension of the space over the real field
|
|
439
|
+
- ``name`` -- (default: ``None``) string; name (symbol) given to the
|
|
440
|
+
Euclidean space; if ``None``, the name will be set to ``'E^n'``
|
|
441
|
+
- ``latex_name`` -- (default: ``None``) string; LaTeX symbol to
|
|
442
|
+
denote the space; if ``None``, it is set to ``'\mathbb{E}^{n}'`` if
|
|
443
|
+
``name`` is ``None`` and to ``name`` otherwise
|
|
444
|
+
- ``coordinates`` -- (default: ``'Cartesian'``) string describing the
|
|
445
|
+
type of coordinates to be initialized at the Euclidean space
|
|
446
|
+
creation; allowed values are
|
|
447
|
+
|
|
448
|
+
- ``'Cartesian'`` (canonical coordinates on `\RR^n`)
|
|
449
|
+
- ``'polar'`` for ``n=2`` only (see
|
|
450
|
+
:meth:`~sage.manifolds.differentiable.examples.euclidean.EuclideanPlane.polar_coordinates`)
|
|
451
|
+
- ``'spherical'`` for ``n=3`` only (see
|
|
452
|
+
:meth:`~sage.manifolds.differentiable.examples.euclidean.Euclidean3dimSpace.spherical_coordinates`)
|
|
453
|
+
- ``'cylindrical'`` for ``n=3`` only (see
|
|
454
|
+
:meth:`~sage.manifolds.differentiable.examples.euclidean.Euclidean3dimSpace.cylindrical_coordinates`)
|
|
455
|
+
|
|
456
|
+
- ``symbols`` -- (default: ``None``) string defining the coordinate
|
|
457
|
+
text symbols and LaTeX symbols, with the same conventions as the
|
|
458
|
+
argument ``coordinates`` in
|
|
459
|
+
:class:`~sage.manifolds.differentiable.chart.RealDiffChart`, namely
|
|
460
|
+
``symbols`` is a string of coordinate fields separated by a blank
|
|
461
|
+
space, where each field contains the coordinate's text symbol and
|
|
462
|
+
possibly the coordinate's LaTeX symbol (when the latter is different
|
|
463
|
+
from the text symbol), both symbols being separated by a colon
|
|
464
|
+
(``:``); if ``None``, the symbols will be automatically generated
|
|
465
|
+
according to the value of ``coordinates``
|
|
466
|
+
- ``metric_name`` -- (default: ``'g'``) string; name (symbol) given to the
|
|
467
|
+
Euclidean metric tensor
|
|
468
|
+
- ``metric_latex_name`` -- (default: ``None``) string; LaTeX symbol to
|
|
469
|
+
denote the Euclidean metric tensor; if none is provided, it is set to
|
|
470
|
+
``metric_name``
|
|
471
|
+
- ``start_index`` -- (default: 1) integer; lower value of the range of
|
|
472
|
+
indices used for "indexed objects" in the Euclidean space, e.g.
|
|
473
|
+
coordinates of a chart
|
|
474
|
+
- ``names`` -- (default: ``None``) unused argument, except if
|
|
475
|
+
``symbols`` is not provided; it must then be a tuple containing
|
|
476
|
+
the coordinate symbols (this is guaranteed if the shortcut operator
|
|
477
|
+
``<,>`` is used)
|
|
478
|
+
|
|
479
|
+
If ``names`` is specified, then ``n`` does not have to be specified.
|
|
480
|
+
|
|
481
|
+
EXAMPLES:
|
|
482
|
+
|
|
483
|
+
Constructing a 2-dimensional Euclidean space::
|
|
484
|
+
|
|
485
|
+
sage: E = EuclideanSpace(2); E
|
|
486
|
+
Euclidean plane E^2
|
|
487
|
+
|
|
488
|
+
Each call to :class:`EuclideanSpace` creates a different object::
|
|
489
|
+
|
|
490
|
+
sage: E1 = EuclideanSpace(2)
|
|
491
|
+
sage: E1 is E
|
|
492
|
+
False
|
|
493
|
+
sage: E1 == E
|
|
494
|
+
False
|
|
495
|
+
|
|
496
|
+
The LaTeX symbol of the Euclidean space is by default `\mathbb{E}^n`,
|
|
497
|
+
where `n` is the dimension::
|
|
498
|
+
|
|
499
|
+
sage: latex(E)
|
|
500
|
+
\mathbb{E}^{2}
|
|
501
|
+
|
|
502
|
+
But both the name and LaTeX names of the Euclidean space can be
|
|
503
|
+
customized::
|
|
504
|
+
|
|
505
|
+
sage: F = EuclideanSpace(2, name='F', latex_name=r'\mathcal{F}'); F
|
|
506
|
+
Euclidean plane F
|
|
507
|
+
sage: latex(F)
|
|
508
|
+
\mathcal{F}
|
|
509
|
+
|
|
510
|
+
By default, a Euclidean space is created with a single coordinate chart:
|
|
511
|
+
that of Cartesian coordinates::
|
|
512
|
+
|
|
513
|
+
sage: E.atlas()
|
|
514
|
+
[Chart (E^2, (x, y))]
|
|
515
|
+
sage: E.cartesian_coordinates()
|
|
516
|
+
Chart (E^2, (x, y))
|
|
517
|
+
sage: E.default_chart() is E.cartesian_coordinates()
|
|
518
|
+
True
|
|
519
|
+
|
|
520
|
+
The coordinate variables can be initialized, as the Python variables
|
|
521
|
+
``x`` and ``y``, by::
|
|
522
|
+
|
|
523
|
+
sage: x, y = E.cartesian_coordinates()[:]
|
|
524
|
+
|
|
525
|
+
However, it is possible to both construct the Euclidean space and
|
|
526
|
+
initialize the coordinate variables in a single stage, thanks to
|
|
527
|
+
SageMath operator ``<,>``::
|
|
528
|
+
|
|
529
|
+
sage: E.<x,y> = EuclideanSpace()
|
|
530
|
+
|
|
531
|
+
Note that providing the dimension as an argument of ``EuclideanSpace`` is
|
|
532
|
+
not necessary in that case, since it can be deduced from the number of
|
|
533
|
+
coordinates within ``<,>``. Besides, the coordinate symbols can be
|
|
534
|
+
customized::
|
|
535
|
+
|
|
536
|
+
sage: E.<X,Y> = EuclideanSpace()
|
|
537
|
+
sage: E.cartesian_coordinates()
|
|
538
|
+
Chart (E^2, (X, Y))
|
|
539
|
+
|
|
540
|
+
By default, the LaTeX symbols of the coordinates coincide with the text
|
|
541
|
+
ones::
|
|
542
|
+
|
|
543
|
+
sage: latex(X+Y)
|
|
544
|
+
X + Y
|
|
545
|
+
|
|
546
|
+
However, it is possible to customize them, via the argument ``symbols``,
|
|
547
|
+
which must be a string, usually prefixed by ``r`` (for *raw* string, in
|
|
548
|
+
order to allow for the backslash character of LaTeX expressions). This
|
|
549
|
+
string contains the coordinate fields separated by a blank space; each
|
|
550
|
+
field contains the coordinate's text symbol and possibly the coordinate's
|
|
551
|
+
LaTeX symbol (when the latter is different from the text symbol), both
|
|
552
|
+
symbols being separated by a colon (``:``)::
|
|
553
|
+
|
|
554
|
+
sage: E.<xi,ze> = EuclideanSpace(symbols=r"xi:\xi ze:\zeta")
|
|
555
|
+
sage: E.cartesian_coordinates()
|
|
556
|
+
Chart (E^2, (xi, ze))
|
|
557
|
+
sage: latex(xi+ze)
|
|
558
|
+
{\xi} + {\zeta}
|
|
559
|
+
|
|
560
|
+
Thanks to the argument ``coordinates``, a Euclidean space can be
|
|
561
|
+
constructed with curvilinear coordinates initialized instead of the
|
|
562
|
+
Cartesian ones::
|
|
563
|
+
|
|
564
|
+
sage: E.<r,ph> = EuclideanSpace(coordinates='polar')
|
|
565
|
+
sage: E.atlas() # no Cartesian coordinates have been constructed
|
|
566
|
+
[Chart (E^2, (r, ph))]
|
|
567
|
+
sage: polar = E.polar_coordinates(); polar
|
|
568
|
+
Chart (E^2, (r, ph))
|
|
569
|
+
sage: E.default_chart() is polar
|
|
570
|
+
True
|
|
571
|
+
sage: latex(r+ph)
|
|
572
|
+
{\phi} + r
|
|
573
|
+
|
|
574
|
+
The Cartesian coordinates, along with the transition maps to and from
|
|
575
|
+
the curvilinear coordinates, can be constructed at any time by::
|
|
576
|
+
|
|
577
|
+
sage: cartesian.<x,y> = E.cartesian_coordinates()
|
|
578
|
+
sage: E.atlas() # both polar and Cartesian coordinates now exist
|
|
579
|
+
[Chart (E^2, (r, ph)), Chart (E^2, (x, y))]
|
|
580
|
+
|
|
581
|
+
The transition maps have been initialized by the command
|
|
582
|
+
``E.cartesian_coordinates()``::
|
|
583
|
+
|
|
584
|
+
sage: E.coord_change(polar, cartesian).display()
|
|
585
|
+
x = r*cos(ph)
|
|
586
|
+
y = r*sin(ph)
|
|
587
|
+
sage: E.coord_change(cartesian, polar).display()
|
|
588
|
+
r = sqrt(x^2 + y^2)
|
|
589
|
+
ph = arctan2(y, x)
|
|
590
|
+
|
|
591
|
+
The default name of the Euclidean metric tensor is `g`::
|
|
592
|
+
|
|
593
|
+
sage: E.metric()
|
|
594
|
+
Riemannian metric g on the Euclidean plane E^2
|
|
595
|
+
sage: latex(_)
|
|
596
|
+
g
|
|
597
|
+
|
|
598
|
+
But this can be customized::
|
|
599
|
+
|
|
600
|
+
sage: E = EuclideanSpace(2, metric_name='h')
|
|
601
|
+
sage: E.metric()
|
|
602
|
+
Riemannian metric h on the Euclidean plane E^2
|
|
603
|
+
sage: latex(_)
|
|
604
|
+
h
|
|
605
|
+
sage: E = EuclideanSpace(2, metric_latex_name=r'\mathbf{g}')
|
|
606
|
+
sage: E.metric()
|
|
607
|
+
Riemannian metric g on the Euclidean plane E^2
|
|
608
|
+
sage: latex(_)
|
|
609
|
+
\mathbf{g}
|
|
610
|
+
|
|
611
|
+
A 4-dimensional Euclidean space::
|
|
612
|
+
|
|
613
|
+
sage: E = EuclideanSpace(4); E
|
|
614
|
+
4-dimensional Euclidean space E^4
|
|
615
|
+
sage: latex(E)
|
|
616
|
+
\mathbb{E}^{4}
|
|
617
|
+
|
|
618
|
+
``E`` is both a real smooth manifold of dimension `4` and a complete metric
|
|
619
|
+
space::
|
|
620
|
+
|
|
621
|
+
sage: E.category()
|
|
622
|
+
Join of Category of smooth manifolds over Real Field with 53 bits of
|
|
623
|
+
precision and Category of connected manifolds over Real Field with
|
|
624
|
+
53 bits of precision and Category of complete metric spaces
|
|
625
|
+
sage: dim(E)
|
|
626
|
+
4
|
|
627
|
+
|
|
628
|
+
It is endowed with a default coordinate chart, which is that of
|
|
629
|
+
Cartesian coordinates `(x_1,x_2,x_3,x_4)`::
|
|
630
|
+
|
|
631
|
+
sage: E.atlas()
|
|
632
|
+
[Chart (E^4, (x1, x2, x3, x4))]
|
|
633
|
+
sage: E.default_chart()
|
|
634
|
+
Chart (E^4, (x1, x2, x3, x4))
|
|
635
|
+
sage: E.default_chart() is E.cartesian_coordinates()
|
|
636
|
+
True
|
|
637
|
+
|
|
638
|
+
``E`` is also endowed with a default metric tensor, which defines the
|
|
639
|
+
Euclidean scalar product::
|
|
640
|
+
|
|
641
|
+
sage: g = E.metric(); g
|
|
642
|
+
Riemannian metric g on the 4-dimensional Euclidean space E^4
|
|
643
|
+
sage: g.display()
|
|
644
|
+
g = dx1⊗dx1 + dx2⊗dx2 + dx3⊗dx3 + dx4⊗dx4
|
|
645
|
+
"""
|
|
646
|
+
@staticmethod
|
|
647
|
+
def __classcall_private__(cls, n=None, name=None, latex_name=None,
|
|
648
|
+
coordinates='Cartesian', symbols=None,
|
|
649
|
+
metric_name='g', metric_latex_name=None,
|
|
650
|
+
start_index=1, names=None, unique_tag=None):
|
|
651
|
+
r"""
|
|
652
|
+
Determine the correct class to return based upon the input.
|
|
653
|
+
|
|
654
|
+
TESTS::
|
|
655
|
+
|
|
656
|
+
sage: E2.<x,y> = EuclideanSpace(); E2
|
|
657
|
+
Euclidean plane E^2
|
|
658
|
+
sage: type(E2)
|
|
659
|
+
<class 'sage.manifolds.differentiable.examples.euclidean.EuclideanPlane_with_category'>
|
|
660
|
+
|
|
661
|
+
sage: E3.<r,t,p> = EuclideanSpace(coordinates='spherical'); E3
|
|
662
|
+
Euclidean space E^3
|
|
663
|
+
sage: type(E3)
|
|
664
|
+
<class 'sage.manifolds.differentiable.examples.euclidean.Euclidean3dimSpace_with_category'>
|
|
665
|
+
sage: E3.default_frame()._latex_indices
|
|
666
|
+
(r, {\theta}, {\phi})
|
|
667
|
+
"""
|
|
668
|
+
if n is None:
|
|
669
|
+
if names is None:
|
|
670
|
+
raise ValueError("either n or names must be specified")
|
|
671
|
+
n = len(names)
|
|
672
|
+
|
|
673
|
+
# Parse names into symbols
|
|
674
|
+
if names is not None and symbols is None:
|
|
675
|
+
if n == 2:
|
|
676
|
+
names = list(names)
|
|
677
|
+
if coordinates == 'polar':
|
|
678
|
+
if names[1] in ['p', 'ph', 'phi']:
|
|
679
|
+
names[1] += ':\\phi'
|
|
680
|
+
elif names[1] in ['t', 'th', 'theta']:
|
|
681
|
+
names[1] += ':\\theta'
|
|
682
|
+
elif n == 3:
|
|
683
|
+
names = list(names)
|
|
684
|
+
# We add the LaTeX symbols when relevant:
|
|
685
|
+
if coordinates == 'spherical':
|
|
686
|
+
if names[1] in ['t', 'th', 'theta']:
|
|
687
|
+
names[1] = names[1] + ':\\theta'
|
|
688
|
+
if names[2] in ['p', 'ph', 'phi']:
|
|
689
|
+
names[2] = names[2] + ':\\phi'
|
|
690
|
+
elif coordinates == 'cylindrical':
|
|
691
|
+
if names[0] in ['rh', 'rho']:
|
|
692
|
+
names[0] = names[0] + ':\\rho'
|
|
693
|
+
if names[1] in ['p', 'ph', 'phi']:
|
|
694
|
+
names[1] = names[1] + ':\\phi'
|
|
695
|
+
|
|
696
|
+
symbols = ' '.join(names)
|
|
697
|
+
|
|
698
|
+
# Technical bit for UniqueRepresentation
|
|
699
|
+
from time import time
|
|
700
|
+
|
|
701
|
+
from sage.misc.prandom import getrandbits
|
|
702
|
+
if unique_tag is None:
|
|
703
|
+
unique_tag = getrandbits(128) * time()
|
|
704
|
+
|
|
705
|
+
if n == 2:
|
|
706
|
+
return EuclideanPlane(name=name, latex_name=latex_name,
|
|
707
|
+
coordinates=coordinates, symbols=symbols,
|
|
708
|
+
metric_name=metric_name,
|
|
709
|
+
metric_latex_name=metric_latex_name,
|
|
710
|
+
start_index=start_index,
|
|
711
|
+
unique_tag=unique_tag)
|
|
712
|
+
if n == 3:
|
|
713
|
+
return Euclidean3dimSpace(name=name, latex_name=latex_name,
|
|
714
|
+
coordinates=coordinates, symbols=symbols,
|
|
715
|
+
metric_name=metric_name,
|
|
716
|
+
metric_latex_name=metric_latex_name,
|
|
717
|
+
start_index=start_index,
|
|
718
|
+
unique_tag=unique_tag)
|
|
719
|
+
|
|
720
|
+
return super().__classcall__(cls,
|
|
721
|
+
n, name=name, latex_name=latex_name,
|
|
722
|
+
coordinates=coordinates, symbols=symbols,
|
|
723
|
+
metric_name=metric_name,
|
|
724
|
+
metric_latex_name=metric_latex_name,
|
|
725
|
+
start_index=start_index,
|
|
726
|
+
unique_tag=unique_tag)
|
|
727
|
+
|
|
728
|
+
def __init__(self, n, name=None, latex_name=None,
|
|
729
|
+
coordinates='Cartesian', symbols=None, metric_name='g',
|
|
730
|
+
metric_latex_name=None, start_index=1, base_manifold=None,
|
|
731
|
+
category=None, init_coord_methods=None,
|
|
732
|
+
unique_tag=None):
|
|
733
|
+
r"""
|
|
734
|
+
Construct a Euclidean space.
|
|
735
|
+
|
|
736
|
+
INPUT:
|
|
737
|
+
|
|
738
|
+
This class also takes the following input:
|
|
739
|
+
|
|
740
|
+
- ``base_manifold`` -- (default: ``None``) if not ``None``, must be
|
|
741
|
+
a Euclidean space; the created object is then an open subset
|
|
742
|
+
of ``base_manifold``
|
|
743
|
+
- ``category`` -- (default: ``None``) to specify the category;
|
|
744
|
+
if ``None``,
|
|
745
|
+
``Manifolds(RR).Smooth() & MetricSpaces().Complete()`` is assumed
|
|
746
|
+
- ``init_coord_methods`` -- (default: ``None``) dictionary of
|
|
747
|
+
methods to initialize the various type of coordinates, with each
|
|
748
|
+
key being a string describing the type of coordinates; to be
|
|
749
|
+
used by derived classes only
|
|
750
|
+
- ``unique_tag`` -- (default: ``None``) tag used to force the
|
|
751
|
+
construction of a new object when all the other arguments have
|
|
752
|
+
been used previously (without ``unique_tag``, the
|
|
753
|
+
:class:`~sage.structure.unique_representation.UniqueRepresentation`
|
|
754
|
+
behavior inherited from
|
|
755
|
+
:class:`~sage.manifolds.differentiable.pseudo_riemannian.PseudoRiemannianManifold`
|
|
756
|
+
would return the previously constructed object corresponding
|
|
757
|
+
to these arguments)
|
|
758
|
+
|
|
759
|
+
TESTS::
|
|
760
|
+
|
|
761
|
+
sage: E = EuclideanSpace(4); E
|
|
762
|
+
4-dimensional Euclidean space E^4
|
|
763
|
+
sage: E.metric()
|
|
764
|
+
Riemannian metric g on the 4-dimensional Euclidean space E^4
|
|
765
|
+
sage: TestSuite(E).run()
|
|
766
|
+
"""
|
|
767
|
+
if name is None:
|
|
768
|
+
name = 'E^{}'.format(n)
|
|
769
|
+
if latex_name is None:
|
|
770
|
+
latex_name = r'\mathbb{E}^{' + str(n) + '}'
|
|
771
|
+
if category is None:
|
|
772
|
+
category = Manifolds(RR).Smooth().Connected() & MetricSpaces().Complete()
|
|
773
|
+
# NB: RR is a proxy for the field of real numbers, until
|
|
774
|
+
# Issue #24456 is ready
|
|
775
|
+
PseudoRiemannianManifold.__init__(self, n, name, metric_name=metric_name,
|
|
776
|
+
signature=n, base_manifold=base_manifold,
|
|
777
|
+
latex_name=latex_name,
|
|
778
|
+
metric_latex_name=metric_latex_name,
|
|
779
|
+
start_index=start_index,
|
|
780
|
+
category=category)
|
|
781
|
+
if symbols is None:
|
|
782
|
+
if n == 1:
|
|
783
|
+
if coordinates == 'Cartesian':
|
|
784
|
+
symbols = 'x'
|
|
785
|
+
else:
|
|
786
|
+
raise TypeError("unknown coordinate type")
|
|
787
|
+
elif n > 3:
|
|
788
|
+
if coordinates == 'Cartesian':
|
|
789
|
+
symbols = ''
|
|
790
|
+
for i in self.irange():
|
|
791
|
+
symbols += "x{}".format(i) + r":x_{" + str(i) + r"} "
|
|
792
|
+
symbols = symbols[:-1]
|
|
793
|
+
else:
|
|
794
|
+
raise TypeError("unknown coordinate type")
|
|
795
|
+
else:
|
|
796
|
+
raise NotImplementedError("dimension not implemented yet")
|
|
797
|
+
self._cartesian_chart = None # to be constructed later if necessary
|
|
798
|
+
if init_coord_methods is None:
|
|
799
|
+
self._init_coordinates = {'Cartesian': self._init_cartesian}
|
|
800
|
+
else:
|
|
801
|
+
self._init_coordinates = init_coord_methods
|
|
802
|
+
self._init_coordinates[coordinates](symbols)
|
|
803
|
+
|
|
804
|
+
def _repr_(self):
|
|
805
|
+
r"""
|
|
806
|
+
Return a string representation of ``self``.
|
|
807
|
+
|
|
808
|
+
TESTS::
|
|
809
|
+
|
|
810
|
+
sage: E = EuclideanSpace(4)
|
|
811
|
+
sage: E._repr_()
|
|
812
|
+
'4-dimensional Euclidean space E^4'
|
|
813
|
+
sage: E # indirect doctest
|
|
814
|
+
4-dimensional Euclidean space E^4
|
|
815
|
+
"""
|
|
816
|
+
return "{}-dimensional Euclidean space {}".format(self._dim, self._name)
|
|
817
|
+
|
|
818
|
+
def _first_ngens(self, n):
|
|
819
|
+
r"""
|
|
820
|
+
Return the list of coordinates of the default chart.
|
|
821
|
+
|
|
822
|
+
This is useful only for the use of Sage preparser::
|
|
823
|
+
|
|
824
|
+
sage: preparse("E.<x,y,z> = EuclideanSpace()")
|
|
825
|
+
"E = EuclideanSpace(names=('x', 'y', 'z',));
|
|
826
|
+
(x, y, z,) = E._first_ngens(3)"
|
|
827
|
+
|
|
828
|
+
TESTS::
|
|
829
|
+
|
|
830
|
+
sage: E = EuclideanSpace(2)
|
|
831
|
+
sage: E._first_ngens(2)
|
|
832
|
+
(x, y)
|
|
833
|
+
sage: E.<u,v> = EuclideanSpace()
|
|
834
|
+
sage: E._first_ngens(2)
|
|
835
|
+
(u, v)
|
|
836
|
+
"""
|
|
837
|
+
return self._def_chart[:]
|
|
838
|
+
|
|
839
|
+
def _init_cartesian(self, symbols):
|
|
840
|
+
r"""
|
|
841
|
+
Construct the chart of Cartesian coordinates and initialize the
|
|
842
|
+
components of the metric tensor in it.
|
|
843
|
+
|
|
844
|
+
TESTS::
|
|
845
|
+
|
|
846
|
+
sage: E = EuclideanSpace(2)
|
|
847
|
+
sage: E._init_cartesian('x y')
|
|
848
|
+
"""
|
|
849
|
+
chart = self.chart(coordinates=symbols)
|
|
850
|
+
self._cartesian_chart = chart
|
|
851
|
+
frame = chart.frame()
|
|
852
|
+
# Renaming (∂/∂x, ∂/∂y, ...) to (e_x, e_y, ...):
|
|
853
|
+
coords = chart[:]
|
|
854
|
+
frame.set_name('e',
|
|
855
|
+
indices=tuple(str(x) for x in coords),
|
|
856
|
+
latex_indices=tuple(latex(x) for x in coords))
|
|
857
|
+
g = self.metric()
|
|
858
|
+
gc = g.add_comp(frame)
|
|
859
|
+
for i in self.irange():
|
|
860
|
+
gc[[i, i]] = self.one_scalar_field()
|
|
861
|
+
nabla = g.connection(init_coef=False) # False to avoid any computation
|
|
862
|
+
nabla.add_coef(frame) # initialize a zero set of coefficients
|
|
863
|
+
|
|
864
|
+
def cartesian_coordinates(self, symbols=None, names=None):
|
|
865
|
+
r"""
|
|
866
|
+
Return the chart of Cartesian coordinates, possibly creating it if it
|
|
867
|
+
does not already exist.
|
|
868
|
+
|
|
869
|
+
INPUT:
|
|
870
|
+
|
|
871
|
+
- ``symbols`` -- (default: ``None``) string defining the coordinate
|
|
872
|
+
text symbols and LaTeX symbols, with the same conventions as
|
|
873
|
+
the argument ``coordinates`` in
|
|
874
|
+
:class:`~sage.manifolds.differentiable.chart.RealDiffChart`; this is
|
|
875
|
+
used only if the Cartesian chart has not been already defined; if
|
|
876
|
+
``None`` the symbols are generated as `(x_1,\ldots,x_n)`.
|
|
877
|
+
- ``names`` -- (default: ``None``) unused argument, except if
|
|
878
|
+
``symbols`` is not provided; it must be a tuple containing
|
|
879
|
+
the coordinate symbols (this is guaranteed if the shortcut operator
|
|
880
|
+
``<,>`` is used)
|
|
881
|
+
|
|
882
|
+
OUTPUT:
|
|
883
|
+
|
|
884
|
+
- the chart of Cartesian coordinates, as an instance of
|
|
885
|
+
:class:`~sage.manifolds.differentiable.chart.RealDiffChart`
|
|
886
|
+
|
|
887
|
+
EXAMPLES::
|
|
888
|
+
|
|
889
|
+
sage: E = EuclideanSpace(4)
|
|
890
|
+
sage: X = E.cartesian_coordinates(); X
|
|
891
|
+
Chart (E^4, (x1, x2, x3, x4))
|
|
892
|
+
sage: X.coord_range()
|
|
893
|
+
x1: (-oo, +oo); x2: (-oo, +oo); x3: (-oo, +oo); x4: (-oo, +oo)
|
|
894
|
+
sage: X[2]
|
|
895
|
+
x2
|
|
896
|
+
sage: X[:]
|
|
897
|
+
(x1, x2, x3, x4)
|
|
898
|
+
sage: latex(X[:])
|
|
899
|
+
\left({x_{1}}, {x_{2}}, {x_{3}}, {x_{4}}\right)
|
|
900
|
+
"""
|
|
901
|
+
if self._cartesian_chart is None:
|
|
902
|
+
if symbols is None:
|
|
903
|
+
symbols = ''
|
|
904
|
+
if names is None:
|
|
905
|
+
for i in self.irange():
|
|
906
|
+
symbols += "x{}".format(i) + r":x_{" + str(i) + r"} "
|
|
907
|
+
else:
|
|
908
|
+
for x in names:
|
|
909
|
+
symbols += x + ' '
|
|
910
|
+
symbols = symbols[:-1]
|
|
911
|
+
self._init_cartesian(symbols)
|
|
912
|
+
return self._cartesian_chart
|
|
913
|
+
|
|
914
|
+
def cartesian_frame(self):
|
|
915
|
+
r"""
|
|
916
|
+
Return the orthonormal vector frame associated with Cartesian
|
|
917
|
+
coordinates.
|
|
918
|
+
|
|
919
|
+
OUTPUT: :class:`~sage.manifolds.differentiable.vectorframe.CoordFrame`
|
|
920
|
+
|
|
921
|
+
EXAMPLES::
|
|
922
|
+
|
|
923
|
+
sage: E = EuclideanSpace(2)
|
|
924
|
+
sage: E.cartesian_frame()
|
|
925
|
+
Coordinate frame (E^2, (e_x,e_y))
|
|
926
|
+
sage: E.cartesian_frame()[1]
|
|
927
|
+
Vector field e_x on the Euclidean plane E^2
|
|
928
|
+
sage: E.cartesian_frame()[:]
|
|
929
|
+
(Vector field e_x on the Euclidean plane E^2,
|
|
930
|
+
Vector field e_y on the Euclidean plane E^2)
|
|
931
|
+
|
|
932
|
+
For Cartesian coordinates, the orthonormal frame coincides with the
|
|
933
|
+
coordinate frame::
|
|
934
|
+
|
|
935
|
+
sage: E.cartesian_frame() is E.cartesian_coordinates().frame()
|
|
936
|
+
True
|
|
937
|
+
"""
|
|
938
|
+
if self._cartesian_chart is None:
|
|
939
|
+
self.cartesian_coordinates() # creates the Cartesian chart
|
|
940
|
+
# Since the coordinate frame of Cartesian coordinates is orthonormal,
|
|
941
|
+
# we simply return this frame:
|
|
942
|
+
return self._cartesian_chart.frame()
|
|
943
|
+
|
|
944
|
+
def dist(self, p, q):
|
|
945
|
+
r"""
|
|
946
|
+
Euclidean distance between two points.
|
|
947
|
+
|
|
948
|
+
INPUT:
|
|
949
|
+
|
|
950
|
+
- ``p`` -- an element of ``self``
|
|
951
|
+
- ``q`` -- an element of ``self``
|
|
952
|
+
|
|
953
|
+
OUTPUT:
|
|
954
|
+
|
|
955
|
+
- the Euclidean distance `d(p, q)`
|
|
956
|
+
|
|
957
|
+
EXAMPLES::
|
|
958
|
+
|
|
959
|
+
sage: E.<x,y> = EuclideanSpace()
|
|
960
|
+
sage: p = E((1,0))
|
|
961
|
+
sage: q = E((0,2))
|
|
962
|
+
sage: E.dist(p, q)
|
|
963
|
+
sqrt(5)
|
|
964
|
+
sage: p.dist(q) # indirect doctest
|
|
965
|
+
sqrt(5)
|
|
966
|
+
"""
|
|
967
|
+
chart = self.cartesian_coordinates()
|
|
968
|
+
coords_p = chart(p)
|
|
969
|
+
coords_q = chart(q)
|
|
970
|
+
d2 = 0
|
|
971
|
+
for xp, xq in zip(coords_p, coords_q):
|
|
972
|
+
dx = xp - xq
|
|
973
|
+
d2 += dx*dx
|
|
974
|
+
return sqrt(d2)
|
|
975
|
+
|
|
976
|
+
def sphere(self, radius=1, center=None, name=None, latex_name=None,
|
|
977
|
+
coordinates='spherical', names=None):
|
|
978
|
+
r"""
|
|
979
|
+
Return an `(n-1)`-sphere smoothly embedded in ``self``.
|
|
980
|
+
|
|
981
|
+
INPUT:
|
|
982
|
+
|
|
983
|
+
- ``radius`` -- (default: ``1``) the radius greater than 1 of the sphere
|
|
984
|
+
- ``center`` -- (default: ``None``) point on ``self`` representing the
|
|
985
|
+
barycenter of the sphere
|
|
986
|
+
- ``name`` -- (default: ``None``) string; name (symbol) given to the
|
|
987
|
+
sphere; if ``None``, the name will be generated according to the input
|
|
988
|
+
- ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote
|
|
989
|
+
the sphere; if ``None``, the symbol will be generated according to
|
|
990
|
+
the input
|
|
991
|
+
- ``coordinates`` -- (default: ``'spherical'``) string describing the
|
|
992
|
+
type of coordinates to be initialized at the sphere's creation;
|
|
993
|
+
allowed values are
|
|
994
|
+
|
|
995
|
+
- ``'spherical'`` spherical coordinates (see
|
|
996
|
+
:meth:`~sage.manifolds.differentiable.examples.sphere.Sphere.spherical_coordinates`))
|
|
997
|
+
- ``'stereographic'`` stereographic coordinates given by the
|
|
998
|
+
stereographic projection (see
|
|
999
|
+
:meth:`~sage.manifolds.differentiable.examples.sphere.Sphere.stereographic_coordinates`)
|
|
1000
|
+
|
|
1001
|
+
- ``names`` -- (default: ``None``) must be a tuple containing
|
|
1002
|
+
the coordinate symbols (this guarantees the shortcut operator
|
|
1003
|
+
``<,>`` to function); if ``None``, the usual conventions are used (see
|
|
1004
|
+
examples in
|
|
1005
|
+
:class:`~sage.manifolds.differentiable.examples.sphere.Sphere`
|
|
1006
|
+
for details)
|
|
1007
|
+
|
|
1008
|
+
EXAMPLES:
|
|
1009
|
+
|
|
1010
|
+
Define a 2-sphere with radius 2 centered at `(1,2,3)` in Cartesian
|
|
1011
|
+
coordinates::
|
|
1012
|
+
|
|
1013
|
+
sage: E3 = EuclideanSpace(3)
|
|
1014
|
+
sage: c = E3.point((1,2,3), name='c'); c
|
|
1015
|
+
Point c on the Euclidean space E^3
|
|
1016
|
+
sage: S2_2 = E3.sphere(radius=2, center=c); S2_2
|
|
1017
|
+
2-sphere S^2_2(c) of radius 2 smoothly embedded in the Euclidean
|
|
1018
|
+
space E^3 centered at the Point c
|
|
1019
|
+
|
|
1020
|
+
The ambient space is precisely our previously defined Euclidean space::
|
|
1021
|
+
|
|
1022
|
+
sage: S2_2.ambient() is E3
|
|
1023
|
+
True
|
|
1024
|
+
|
|
1025
|
+
The embedding into Euclidean space::
|
|
1026
|
+
|
|
1027
|
+
sage: S2_2.embedding().display()
|
|
1028
|
+
iota: S^2_2(c) → E^3
|
|
1029
|
+
on A: (theta, phi) ↦ (x, y, z) = (2*cos(phi)*sin(theta) + 1,
|
|
1030
|
+
2*sin(phi)*sin(theta) + 2,
|
|
1031
|
+
2*cos(theta) + 3)
|
|
1032
|
+
|
|
1033
|
+
See :class:`~sage.manifolds.differentiable.examples.sphere.Sphere`
|
|
1034
|
+
for more examples.
|
|
1035
|
+
"""
|
|
1036
|
+
n = self._dim
|
|
1037
|
+
if n == 1:
|
|
1038
|
+
raise ValueError('Euclidean space must have dimension of at least 2')
|
|
1039
|
+
from sage.manifolds.differentiable.examples.sphere import Sphere
|
|
1040
|
+
return Sphere(n-1, radius=radius, ambient_space=self,
|
|
1041
|
+
center=center, name=name, latex_name=latex_name,
|
|
1042
|
+
coordinates=coordinates, names=names)
|
|
1043
|
+
|
|
1044
|
+
###############################################################################
|
|
1045
|
+
|
|
1046
|
+
|
|
1047
|
+
class EuclideanPlane(EuclideanSpace):
|
|
1048
|
+
r"""
|
|
1049
|
+
Euclidean plane.
|
|
1050
|
+
|
|
1051
|
+
A *Euclidean plane* is an affine space `E`, whose associated vector space
|
|
1052
|
+
is a 2-dimensional vector space over `\RR` and is equipped with a
|
|
1053
|
+
positive definite symmetric bilinear form, called the *scalar product* or
|
|
1054
|
+
*dot product*.
|
|
1055
|
+
|
|
1056
|
+
The class :class:`EuclideanPlane` inherits from
|
|
1057
|
+
:class:`~sage.manifolds.differentiable.pseudo_riemannian.PseudoRiemannianManifold`
|
|
1058
|
+
(via :class:`EuclideanSpace`) since a Euclidean plane can be viewed
|
|
1059
|
+
as a Riemannian manifold that is diffeomorphic to `\RR^2` and that has a
|
|
1060
|
+
flat metric `g`. The Euclidean scalar product is the one defined by the
|
|
1061
|
+
Riemannian metric `g`.
|
|
1062
|
+
|
|
1063
|
+
INPUT:
|
|
1064
|
+
|
|
1065
|
+
- ``name`` -- (default: ``None``) string; name (symbol) given to the
|
|
1066
|
+
Euclidean plane; if ``None``, the name will be set to ``'E^2'``
|
|
1067
|
+
- ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote the
|
|
1068
|
+
Euclidean plane; if ``None``, it is set to ``'\mathbb{E}^{2}'`` if
|
|
1069
|
+
``name`` is ``None`` and to ``name`` otherwise
|
|
1070
|
+
- ``coordinates`` -- (default: ``'Cartesian'``) string describing the type
|
|
1071
|
+
of coordinates to be initialized at the Euclidean plane creation;
|
|
1072
|
+
allowed values are ``'Cartesian'`` (see :meth:`cartesian_coordinates`)
|
|
1073
|
+
and ``'polar'`` (see :meth:`polar_coordinates`)
|
|
1074
|
+
- ``symbols`` -- (default: ``None``) string defining the coordinate text
|
|
1075
|
+
symbols and LaTeX symbols, with the same conventions as the argument
|
|
1076
|
+
``coordinates`` in
|
|
1077
|
+
:class:`~sage.manifolds.differentiable.chart.RealDiffChart`, namely
|
|
1078
|
+
``symbols`` is a string of coordinate fields separated by a blank space,
|
|
1079
|
+
where each field contains the coordinate's text symbol and possibly the
|
|
1080
|
+
coordinate's LaTeX symbol (when the latter is different from the text
|
|
1081
|
+
symbol), both symbols being separated by a colon (``:``); if ``None``,
|
|
1082
|
+
the symbols will be automatically generated according to the value of
|
|
1083
|
+
``coordinates``
|
|
1084
|
+
- ``metric_name`` -- (default: ``'g'``) string; name (symbol) given to the
|
|
1085
|
+
Euclidean metric tensor
|
|
1086
|
+
- ``metric_latex_name`` -- (default: ``None``) string; LaTeX symbol to
|
|
1087
|
+
denote the Euclidean metric tensor; if none is provided, it is set to
|
|
1088
|
+
``metric_name``
|
|
1089
|
+
- ``start_index`` -- (default: 1) integer; lower value of the range of
|
|
1090
|
+
indices used for "indexed objects" in the Euclidean plane, e.g.
|
|
1091
|
+
coordinates of a chart
|
|
1092
|
+
- ``base_manifold`` -- (default: ``None``) if not ``None``, must be an
|
|
1093
|
+
Euclidean plane; the created object is then an open subset of ``base_manifold``
|
|
1094
|
+
- ``category`` -- (default: ``None``) to specify the category; if ``None``,
|
|
1095
|
+
``Manifolds(RR).Smooth() & MetricSpaces().Complete()`` is assumed
|
|
1096
|
+
- ``names`` -- (default: ``None``) unused argument, except if
|
|
1097
|
+
``symbols`` is not provided; it must then be a tuple containing
|
|
1098
|
+
the coordinate symbols (this is guaranteed if the shortcut operator
|
|
1099
|
+
``<,>`` is used)
|
|
1100
|
+
- ``init_coord_methods`` -- (default: ``None``) dictionary of methods
|
|
1101
|
+
to initialize the various type of coordinates, with each key being a
|
|
1102
|
+
string describing the type of coordinates; to be used by derived classes
|
|
1103
|
+
only
|
|
1104
|
+
- ``unique_tag`` -- (default: ``None``) tag used to force the construction
|
|
1105
|
+
of a new object when all the other arguments have been used previously
|
|
1106
|
+
(without ``unique_tag``, the
|
|
1107
|
+
:class:`~sage.structure.unique_representation.UniqueRepresentation`
|
|
1108
|
+
behavior inherited from
|
|
1109
|
+
:class:`~sage.manifolds.differentiable.pseudo_riemannian.PseudoRiemannianManifold`
|
|
1110
|
+
would return the previously constructed object corresponding to these
|
|
1111
|
+
arguments)
|
|
1112
|
+
|
|
1113
|
+
EXAMPLES:
|
|
1114
|
+
|
|
1115
|
+
One creates a Euclidean plane ``E`` with::
|
|
1116
|
+
|
|
1117
|
+
sage: E.<x,y> = EuclideanSpace(); E
|
|
1118
|
+
Euclidean plane E^2
|
|
1119
|
+
|
|
1120
|
+
``E`` is both a real smooth manifold of dimension `2` and a complete metric
|
|
1121
|
+
space::
|
|
1122
|
+
|
|
1123
|
+
sage: E.category()
|
|
1124
|
+
Join of Category of smooth manifolds over Real Field with 53 bits of
|
|
1125
|
+
precision and Category of connected manifolds over Real Field with
|
|
1126
|
+
53 bits of precision and Category of complete metric spaces
|
|
1127
|
+
sage: dim(E)
|
|
1128
|
+
2
|
|
1129
|
+
|
|
1130
|
+
It is endowed with a default coordinate chart, which is that
|
|
1131
|
+
of Cartesian coordinates `(x,y)`::
|
|
1132
|
+
|
|
1133
|
+
sage: E.atlas()
|
|
1134
|
+
[Chart (E^2, (x, y))]
|
|
1135
|
+
sage: E.default_chart()
|
|
1136
|
+
Chart (E^2, (x, y))
|
|
1137
|
+
sage: cartesian = E.cartesian_coordinates()
|
|
1138
|
+
sage: cartesian is E.default_chart()
|
|
1139
|
+
True
|
|
1140
|
+
|
|
1141
|
+
A point of ``E``::
|
|
1142
|
+
|
|
1143
|
+
sage: p = E((3,-2)); p
|
|
1144
|
+
Point on the Euclidean plane E^2
|
|
1145
|
+
sage: cartesian(p)
|
|
1146
|
+
(3, -2)
|
|
1147
|
+
sage: p in E
|
|
1148
|
+
True
|
|
1149
|
+
sage: p.parent() is E
|
|
1150
|
+
True
|
|
1151
|
+
|
|
1152
|
+
``E`` is endowed with a default metric tensor, which defines the
|
|
1153
|
+
Euclidean scalar product::
|
|
1154
|
+
|
|
1155
|
+
sage: g = E.metric(); g
|
|
1156
|
+
Riemannian metric g on the Euclidean plane E^2
|
|
1157
|
+
sage: g.display()
|
|
1158
|
+
g = dx⊗dx + dy⊗dy
|
|
1159
|
+
|
|
1160
|
+
Curvilinear coordinates can be introduced on ``E``: see
|
|
1161
|
+
:meth:`polar_coordinates`.
|
|
1162
|
+
|
|
1163
|
+
.. SEEALSO::
|
|
1164
|
+
|
|
1165
|
+
:ref:`EuclideanSpace_example1`
|
|
1166
|
+
"""
|
|
1167
|
+
def __init__(self, name=None, latex_name=None, coordinates='Cartesian',
|
|
1168
|
+
symbols=None, metric_name='g', metric_latex_name=None,
|
|
1169
|
+
start_index=1, base_manifold=None, category=None, unique_tag=None):
|
|
1170
|
+
r"""
|
|
1171
|
+
Construct a Euclidean plane.
|
|
1172
|
+
|
|
1173
|
+
TESTS::
|
|
1174
|
+
|
|
1175
|
+
sage: E = EuclideanSpace(2); E
|
|
1176
|
+
Euclidean plane E^2
|
|
1177
|
+
sage: E.metric()
|
|
1178
|
+
Riemannian metric g on the Euclidean plane E^2
|
|
1179
|
+
sage: TestSuite(E).run()
|
|
1180
|
+
"""
|
|
1181
|
+
if coordinates not in ['Cartesian', 'polar']:
|
|
1182
|
+
raise TypeError("unknown coordinate type")
|
|
1183
|
+
if symbols is None:
|
|
1184
|
+
if coordinates == 'Cartesian':
|
|
1185
|
+
symbols = 'x y'
|
|
1186
|
+
elif coordinates == 'polar':
|
|
1187
|
+
symbols = 'r ph:\\phi'
|
|
1188
|
+
self._polar_chart = None # to be constructed later if necessary
|
|
1189
|
+
self._polar_frame = None # orthonormal frame associated to polar coord
|
|
1190
|
+
init_coord_methods = {'Cartesian': self._init_cartesian,
|
|
1191
|
+
'polar': self._init_polar}
|
|
1192
|
+
EuclideanSpace.__init__(self, 2, name=name,
|
|
1193
|
+
latex_name=latex_name,
|
|
1194
|
+
coordinates=coordinates,
|
|
1195
|
+
symbols=symbols,
|
|
1196
|
+
metric_name=metric_name,
|
|
1197
|
+
metric_latex_name=metric_latex_name,
|
|
1198
|
+
start_index=start_index,
|
|
1199
|
+
base_manifold=base_manifold, category=category,
|
|
1200
|
+
init_coord_methods=init_coord_methods)
|
|
1201
|
+
if coordinates == 'polar':
|
|
1202
|
+
# The default frame is the polar coordinate frame; we change it
|
|
1203
|
+
# to the orthonormal polar frame
|
|
1204
|
+
self.set_default_frame(self.polar_frame())
|
|
1205
|
+
|
|
1206
|
+
def _repr_(self):
|
|
1207
|
+
r"""
|
|
1208
|
+
Return a string representation of ``self``.
|
|
1209
|
+
|
|
1210
|
+
TESTS::
|
|
1211
|
+
|
|
1212
|
+
sage: E = EuclideanSpace(2)
|
|
1213
|
+
sage: E._repr_()
|
|
1214
|
+
'Euclidean plane E^2'
|
|
1215
|
+
sage: E # indirect doctest
|
|
1216
|
+
Euclidean plane E^2
|
|
1217
|
+
sage: E = EuclideanSpace(2, name='E')
|
|
1218
|
+
sage: E._repr_()
|
|
1219
|
+
'Euclidean plane E'
|
|
1220
|
+
"""
|
|
1221
|
+
return "Euclidean plane {}".format(self._name)
|
|
1222
|
+
|
|
1223
|
+
def _init_polar(self, symbols):
|
|
1224
|
+
r"""
|
|
1225
|
+
Construct the chart of polar coordinates and initialize the
|
|
1226
|
+
components of the metric tensor in it.
|
|
1227
|
+
|
|
1228
|
+
TESTS::
|
|
1229
|
+
|
|
1230
|
+
sage: E = EuclideanSpace(2)
|
|
1231
|
+
sage: E.atlas()
|
|
1232
|
+
[Chart (E^2, (x, y))]
|
|
1233
|
+
sage: E._init_polar(r"R Phi:\Phi")
|
|
1234
|
+
sage: E.atlas()
|
|
1235
|
+
[Chart (E^2, (x, y)), Chart (E^2, (R, Phi))]
|
|
1236
|
+
"""
|
|
1237
|
+
coords = symbols.split() # list of strings, one per coordinate
|
|
1238
|
+
# Adding the coordinate ranges:
|
|
1239
|
+
coordinates = (coords[0] + ':(0,+oo) ' + coords[1]
|
|
1240
|
+
+ ':(0,2*pi):periodic')
|
|
1241
|
+
chart = self.chart(coordinates=coordinates)
|
|
1242
|
+
self._polar_chart = chart
|
|
1243
|
+
frame = chart.frame()
|
|
1244
|
+
# Initialization of the metric components and the associated
|
|
1245
|
+
# Christoffel symbols
|
|
1246
|
+
g = self.metric()
|
|
1247
|
+
gc = g.add_comp(frame)
|
|
1248
|
+
i1 = self._sindex
|
|
1249
|
+
i2 = i1 + 1
|
|
1250
|
+
r, ph = chart[:]
|
|
1251
|
+
gc[i1, i1, chart] = 1
|
|
1252
|
+
gc[i2, i2, chart] = r**2
|
|
1253
|
+
# Orthonormal frame associated with polar coordinates:
|
|
1254
|
+
to_orthonormal = self.automorphism_field()
|
|
1255
|
+
to_orthonormal[frame, i1, i1, chart] = 1
|
|
1256
|
+
to_orthonormal[frame, i2, i2, chart] = 1 / r
|
|
1257
|
+
oframe = frame.new_frame(to_orthonormal, 'e',
|
|
1258
|
+
indices=(str(r), str(ph)),
|
|
1259
|
+
latex_indices=(latex(r), latex(ph)))
|
|
1260
|
+
self._polar_frame = oframe
|
|
1261
|
+
g.comp(oframe)
|
|
1262
|
+
|
|
1263
|
+
def _transition_polar_cartesian(self):
|
|
1264
|
+
r"""
|
|
1265
|
+
Transitions between polar and Cartesian coordinates.
|
|
1266
|
+
|
|
1267
|
+
TESTS::
|
|
1268
|
+
|
|
1269
|
+
sage: E = EuclideanSpace(2)
|
|
1270
|
+
sage: E._init_polar(r"r ph:\phi")
|
|
1271
|
+
sage: E.atlas()
|
|
1272
|
+
[Chart (E^2, (x, y)), Chart (E^2, (r, ph))]
|
|
1273
|
+
sage: E.coord_changes() # no transition map has been defined yet
|
|
1274
|
+
{}
|
|
1275
|
+
sage: E._transition_polar_cartesian()
|
|
1276
|
+
sage: len(E.coord_changes()) # 2 transition maps have been created
|
|
1277
|
+
2
|
|
1278
|
+
|
|
1279
|
+
Tests of the change-of-frame formulas::
|
|
1280
|
+
|
|
1281
|
+
sage: polar = E.polar_coordinates()
|
|
1282
|
+
sage: polar_f = E.polar_frame()
|
|
1283
|
+
sage: cart_f = E.cartesian_frame()
|
|
1284
|
+
sage: E.change_of_frame(cart_f, polar_f)[:, polar]
|
|
1285
|
+
[ cos(ph) -sin(ph)]
|
|
1286
|
+
[ sin(ph) cos(ph)]
|
|
1287
|
+
sage: E.change_of_frame(polar_f, cart_f)[:, polar]
|
|
1288
|
+
[ cos(ph) sin(ph)]
|
|
1289
|
+
[-sin(ph) cos(ph)]
|
|
1290
|
+
"""
|
|
1291
|
+
# Transition maps polar chart <-> Cartesian chart
|
|
1292
|
+
chart_cart = self._cartesian_chart
|
|
1293
|
+
chart_pol = self._polar_chart
|
|
1294
|
+
x, y = chart_cart[:]
|
|
1295
|
+
r, ph = chart_pol[:]
|
|
1296
|
+
pol_to_cart = chart_pol.transition_map(chart_cart,
|
|
1297
|
+
[r*cos(ph), r*sin(ph)])
|
|
1298
|
+
pol_to_cart.set_inverse(sqrt(x**2+y**2), atan2(y,x), check=False)
|
|
1299
|
+
# Automorphism Cartesian frame → orthonormal polar frame:
|
|
1300
|
+
oframe = self._polar_frame
|
|
1301
|
+
cframe = chart_cart.frame()
|
|
1302
|
+
sframe = chart_pol.frame()
|
|
1303
|
+
chg = self._frame_changes
|
|
1304
|
+
cframe_to_oframe = chg[(sframe, oframe)] * chg[(cframe, sframe)]
|
|
1305
|
+
# cframe_to_oframe has been computed only in sframe;
|
|
1306
|
+
# its components in oframe are computed by
|
|
1307
|
+
cmp_of = cframe_to_oframe.comp(oframe)
|
|
1308
|
+
# while its components in cframe are obtained by identifying the
|
|
1309
|
+
# matrices in cframe and oframe:
|
|
1310
|
+
cmp_cf = cframe_to_oframe.add_comp(cframe)
|
|
1311
|
+
for i in self.irange():
|
|
1312
|
+
for j in self.irange():
|
|
1313
|
+
cmp_cf[[i,j]] = cmp_of[[i,j]]
|
|
1314
|
+
# Automorphism orthonormal polar frame → Cartesian frame:
|
|
1315
|
+
oframe_to_cframe = chg[(sframe, cframe)] * chg[(oframe, sframe)]
|
|
1316
|
+
# oframe_to_cframe has been computed only in sframe;
|
|
1317
|
+
# its components in oframe are computed by
|
|
1318
|
+
cmp_of = oframe_to_cframe.comp(oframe)
|
|
1319
|
+
# while its components in cframe are obtained by identifying the
|
|
1320
|
+
# matrices in cframe and oframe:
|
|
1321
|
+
cmp_cf = oframe_to_cframe.add_comp(cframe)
|
|
1322
|
+
for i in self.irange():
|
|
1323
|
+
for j in self.irange():
|
|
1324
|
+
cmp_cf[[i,j]] = cmp_of[[i,j]]
|
|
1325
|
+
# Storage of the results:
|
|
1326
|
+
chg[(cframe, oframe)] = cframe_to_oframe
|
|
1327
|
+
chg[(oframe, cframe)] = oframe_to_cframe
|
|
1328
|
+
vmodule = self.vector_field_module()
|
|
1329
|
+
vmodule.set_change_of_basis(cframe, oframe, cframe_to_oframe,
|
|
1330
|
+
compute_inverse=False)
|
|
1331
|
+
vmodule.set_change_of_basis(oframe, cframe, oframe_to_cframe,
|
|
1332
|
+
compute_inverse=False)
|
|
1333
|
+
|
|
1334
|
+
def cartesian_coordinates(self, symbols=None, names=None):
|
|
1335
|
+
r"""
|
|
1336
|
+
Return the chart of Cartesian coordinates, possibly creating it if it
|
|
1337
|
+
does not already exist.
|
|
1338
|
+
|
|
1339
|
+
INPUT:
|
|
1340
|
+
|
|
1341
|
+
- ``symbols`` -- (default: ``None``) string defining the coordinate
|
|
1342
|
+
text symbols and LaTeX symbols, with the same conventions as the
|
|
1343
|
+
argument ``coordinates`` in
|
|
1344
|
+
:class:`~sage.manifolds.differentiable.chart.RealDiffChart`; this is
|
|
1345
|
+
used only if the Cartesian chart has not been already defined; if
|
|
1346
|
+
``None`` the symbols are generated as `(x,y)`.
|
|
1347
|
+
- ``names`` -- (default: ``None``) unused argument, except if
|
|
1348
|
+
``symbols`` is not provided; it must be a tuple containing
|
|
1349
|
+
the coordinate symbols (this is guaranteed if the shortcut operator
|
|
1350
|
+
``<,>`` is used)
|
|
1351
|
+
|
|
1352
|
+
OUTPUT:
|
|
1353
|
+
|
|
1354
|
+
- the chart of Cartesian coordinates, as an instance of
|
|
1355
|
+
:class:`~sage.manifolds.differentiable.chart.RealDiffChart`
|
|
1356
|
+
|
|
1357
|
+
EXAMPLES::
|
|
1358
|
+
|
|
1359
|
+
sage: E = EuclideanSpace(2)
|
|
1360
|
+
sage: E.cartesian_coordinates()
|
|
1361
|
+
Chart (E^2, (x, y))
|
|
1362
|
+
sage: E.cartesian_coordinates().coord_range()
|
|
1363
|
+
x: (-oo, +oo); y: (-oo, +oo)
|
|
1364
|
+
|
|
1365
|
+
An example where the Cartesian coordinates have not been previously
|
|
1366
|
+
created::
|
|
1367
|
+
|
|
1368
|
+
sage: E = EuclideanSpace(2, coordinates='polar')
|
|
1369
|
+
sage: E.atlas() # only polar coordinates have been initialized
|
|
1370
|
+
[Chart (E^2, (r, ph))]
|
|
1371
|
+
sage: E.cartesian_coordinates(symbols='X Y')
|
|
1372
|
+
Chart (E^2, (X, Y))
|
|
1373
|
+
sage: E.atlas() # the Cartesian chart has been added to the atlas
|
|
1374
|
+
[Chart (E^2, (r, ph)), Chart (E^2, (X, Y))]
|
|
1375
|
+
|
|
1376
|
+
Note that if the Cartesian coordinates have been already initialized,
|
|
1377
|
+
the argument ``symbols`` has no effect::
|
|
1378
|
+
|
|
1379
|
+
sage: E.cartesian_coordinates(symbols='x y')
|
|
1380
|
+
Chart (E^2, (X, Y))
|
|
1381
|
+
|
|
1382
|
+
The coordinate variables are returned by the square bracket operator::
|
|
1383
|
+
|
|
1384
|
+
sage: E.cartesian_coordinates()[1]
|
|
1385
|
+
X
|
|
1386
|
+
sage: E.cartesian_coordinates()[2]
|
|
1387
|
+
Y
|
|
1388
|
+
sage: E.cartesian_coordinates()[:]
|
|
1389
|
+
(X, Y)
|
|
1390
|
+
|
|
1391
|
+
It is also possible to use the operator ``<,>`` to set symbolic
|
|
1392
|
+
variable containing the coordinates::
|
|
1393
|
+
|
|
1394
|
+
sage: E = EuclideanSpace(2, coordinates='polar')
|
|
1395
|
+
sage: cartesian.<u,v> = E.cartesian_coordinates()
|
|
1396
|
+
sage: cartesian
|
|
1397
|
+
Chart (E^2, (u, v))
|
|
1398
|
+
sage: u,v
|
|
1399
|
+
(u, v)
|
|
1400
|
+
|
|
1401
|
+
The command ``cartesian.<u,v> = E.cartesian_coordinates()`` is
|
|
1402
|
+
actually a shortcut for::
|
|
1403
|
+
|
|
1404
|
+
sage: cartesian = E.cartesian_coordinates(symbols='u v')
|
|
1405
|
+
sage: u, v = cartesian[:]
|
|
1406
|
+
"""
|
|
1407
|
+
if self._cartesian_chart is None:
|
|
1408
|
+
if symbols is None:
|
|
1409
|
+
if names is None:
|
|
1410
|
+
symbols = 'x y'
|
|
1411
|
+
else:
|
|
1412
|
+
symbols = names[0] + ' ' + names[1]
|
|
1413
|
+
self._init_cartesian(symbols)
|
|
1414
|
+
if self._polar_chart:
|
|
1415
|
+
self._transition_polar_cartesian()
|
|
1416
|
+
return self._cartesian_chart
|
|
1417
|
+
|
|
1418
|
+
def polar_coordinates(self, symbols=None, names=None):
|
|
1419
|
+
r"""
|
|
1420
|
+
Return the chart of polar coordinates, possibly creating it if it
|
|
1421
|
+
does not already exist.
|
|
1422
|
+
|
|
1423
|
+
INPUT:
|
|
1424
|
+
|
|
1425
|
+
- ``symbols`` -- (default: ``None``) string defining the coordinate
|
|
1426
|
+
text symbols and LaTeX symbols, with the same conventions as the
|
|
1427
|
+
argument ``coordinates`` in
|
|
1428
|
+
:class:`~sage.manifolds.differentiable.chart.RealDiffChart`; this is
|
|
1429
|
+
used only if the polar chart has not been already defined; if
|
|
1430
|
+
``None`` the symbols are generated as `(r,\phi)`.
|
|
1431
|
+
- ``names`` -- (default: ``None``) unused argument, except if
|
|
1432
|
+
``symbols`` is not provided; it must be a tuple containing
|
|
1433
|
+
the coordinate symbols (this is guaranteed if the shortcut operator
|
|
1434
|
+
``<,>`` is used)
|
|
1435
|
+
|
|
1436
|
+
OUTPUT:
|
|
1437
|
+
|
|
1438
|
+
- the chart of polar coordinates, as an instance of
|
|
1439
|
+
:class:`~sage.manifolds.differentiable.chart.RealDiffChart`
|
|
1440
|
+
|
|
1441
|
+
EXAMPLES::
|
|
1442
|
+
|
|
1443
|
+
sage: E = EuclideanSpace(2)
|
|
1444
|
+
sage: E.polar_coordinates()
|
|
1445
|
+
Chart (E^2, (r, ph))
|
|
1446
|
+
sage: latex(_)
|
|
1447
|
+
\left(\mathbb{E}^{2},(r, {\phi})\right)
|
|
1448
|
+
sage: E.polar_coordinates().coord_range()
|
|
1449
|
+
r: (0, +oo); ph: [0, 2*pi] (periodic)
|
|
1450
|
+
|
|
1451
|
+
The relation to Cartesian coordinates is::
|
|
1452
|
+
|
|
1453
|
+
sage: E.coord_change(E.polar_coordinates(),
|
|
1454
|
+
....: E.cartesian_coordinates()).display()
|
|
1455
|
+
x = r*cos(ph)
|
|
1456
|
+
y = r*sin(ph)
|
|
1457
|
+
sage: E.coord_change(E.cartesian_coordinates(),
|
|
1458
|
+
....: E.polar_coordinates()).display()
|
|
1459
|
+
r = sqrt(x^2 + y^2)
|
|
1460
|
+
ph = arctan2(y, x)
|
|
1461
|
+
|
|
1462
|
+
The coordinate variables are returned by the square bracket operator::
|
|
1463
|
+
|
|
1464
|
+
sage: E.polar_coordinates()[1]
|
|
1465
|
+
r
|
|
1466
|
+
sage: E.polar_coordinates()[2]
|
|
1467
|
+
ph
|
|
1468
|
+
sage: E.polar_coordinates()[:]
|
|
1469
|
+
(r, ph)
|
|
1470
|
+
|
|
1471
|
+
They can also be obtained via the operator ``<,>``::
|
|
1472
|
+
|
|
1473
|
+
sage: polar.<r,ph> = E.polar_coordinates(); polar
|
|
1474
|
+
Chart (E^2, (r, ph))
|
|
1475
|
+
sage: r, ph
|
|
1476
|
+
(r, ph)
|
|
1477
|
+
|
|
1478
|
+
Actually, ``polar.<r,ph> = E.polar_coordinates()`` is a shortcut for::
|
|
1479
|
+
|
|
1480
|
+
sage: polar = E.polar_coordinates()
|
|
1481
|
+
sage: r, ph = polar[:]
|
|
1482
|
+
|
|
1483
|
+
The coordinate symbols can be customized::
|
|
1484
|
+
|
|
1485
|
+
sage: E = EuclideanSpace(2)
|
|
1486
|
+
sage: E.polar_coordinates(symbols=r"r th:\theta")
|
|
1487
|
+
Chart (E^2, (r, th))
|
|
1488
|
+
sage: latex(E.polar_coordinates())
|
|
1489
|
+
\left(\mathbb{E}^{2},(r, {\theta})\right)
|
|
1490
|
+
|
|
1491
|
+
Note that if the polar coordinates have been already initialized, the
|
|
1492
|
+
argument ``symbols`` has no effect::
|
|
1493
|
+
|
|
1494
|
+
sage: E.polar_coordinates(symbols=r"R Th:\Theta")
|
|
1495
|
+
Chart (E^2, (r, th))
|
|
1496
|
+
"""
|
|
1497
|
+
if self._polar_chart is None:
|
|
1498
|
+
if symbols is None:
|
|
1499
|
+
if names is None:
|
|
1500
|
+
symbols = 'r ph:\\phi'
|
|
1501
|
+
else:
|
|
1502
|
+
symbols = names[0] + ' ' + names[1]
|
|
1503
|
+
if names[1] in ['p', 'ph', 'phi']:
|
|
1504
|
+
symbols += ':\\phi'
|
|
1505
|
+
elif names[1] in ['t', 'th', 'theta']:
|
|
1506
|
+
symbols += ':\\theta'
|
|
1507
|
+
self._init_polar(symbols)
|
|
1508
|
+
if self._cartesian_chart:
|
|
1509
|
+
self._transition_polar_cartesian()
|
|
1510
|
+
return self._polar_chart
|
|
1511
|
+
|
|
1512
|
+
def polar_frame(self):
|
|
1513
|
+
r"""
|
|
1514
|
+
Return the orthonormal vector frame associated with polar
|
|
1515
|
+
coordinates.
|
|
1516
|
+
|
|
1517
|
+
OUTPUT:
|
|
1518
|
+
|
|
1519
|
+
- instance of
|
|
1520
|
+
:class:`~sage.manifolds.differentiable.vectorframe.VectorFrame`
|
|
1521
|
+
|
|
1522
|
+
EXAMPLES::
|
|
1523
|
+
|
|
1524
|
+
sage: E = EuclideanSpace(2)
|
|
1525
|
+
sage: E.polar_frame()
|
|
1526
|
+
Vector frame (E^2, (e_r,e_ph))
|
|
1527
|
+
sage: E.polar_frame()[1]
|
|
1528
|
+
Vector field e_r on the Euclidean plane E^2
|
|
1529
|
+
sage: E.polar_frame()[:]
|
|
1530
|
+
(Vector field e_r on the Euclidean plane E^2,
|
|
1531
|
+
Vector field e_ph on the Euclidean plane E^2)
|
|
1532
|
+
|
|
1533
|
+
The orthonormal polar frame expressed in terms of the Cartesian one::
|
|
1534
|
+
|
|
1535
|
+
sage: for e in E.polar_frame():
|
|
1536
|
+
....: e.display(E.cartesian_frame(), E.polar_coordinates())
|
|
1537
|
+
e_r = cos(ph) e_x + sin(ph) e_y
|
|
1538
|
+
e_ph = -sin(ph) e_x + cos(ph) e_y
|
|
1539
|
+
|
|
1540
|
+
The orthonormal frame `(e_r, e_\phi)` expressed in terms of the
|
|
1541
|
+
coordinate frame
|
|
1542
|
+
`\left(\frac{\partial}{\partial r},
|
|
1543
|
+
\frac{\partial}{\partial\phi}\right)`::
|
|
1544
|
+
|
|
1545
|
+
sage: for e in E.polar_frame():
|
|
1546
|
+
....: e.display(E.polar_coordinates())
|
|
1547
|
+
e_r = ∂/∂r
|
|
1548
|
+
e_ph = 1/r ∂/∂ph
|
|
1549
|
+
"""
|
|
1550
|
+
if self._polar_frame is None:
|
|
1551
|
+
# create the polar chart and the associated orthonormal frame
|
|
1552
|
+
self.polar_coordinates()
|
|
1553
|
+
return self._polar_frame
|
|
1554
|
+
|
|
1555
|
+
|
|
1556
|
+
###############################################################################
|
|
1557
|
+
|
|
1558
|
+
class Euclidean3dimSpace(EuclideanSpace):
|
|
1559
|
+
r"""
|
|
1560
|
+
3-dimensional Euclidean space.
|
|
1561
|
+
|
|
1562
|
+
A *3-dimensional Euclidean space* is an affine space `E`, whose associated
|
|
1563
|
+
vector space is a 3-dimensional vector space over `\RR` and is equipped
|
|
1564
|
+
with a positive definite symmetric bilinear form, called the *scalar
|
|
1565
|
+
product* or *dot product*.
|
|
1566
|
+
|
|
1567
|
+
The class :class:`Euclidean3dimSpace` inherits from
|
|
1568
|
+
:class:`~sage.manifolds.differentiable.pseudo_riemannian.PseudoRiemannianManifold`
|
|
1569
|
+
(via :class:`EuclideanSpace`) since a 3-dimensional Euclidean space
|
|
1570
|
+
can be viewed as a Riemannian manifold that is diffeomorphic to `\RR^3` and
|
|
1571
|
+
that has a flat metric `g`. The Euclidean scalar product is the one defined
|
|
1572
|
+
by the Riemannian metric `g`.
|
|
1573
|
+
|
|
1574
|
+
INPUT:
|
|
1575
|
+
|
|
1576
|
+
- ``name`` -- (default: ``None``) string; name (symbol) given to the
|
|
1577
|
+
Euclidean 3-space; if ``None``, the name will be set to ``'E^3'``
|
|
1578
|
+
- ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote the
|
|
1579
|
+
Euclidean 3-space; if ``None``, it is set to ``'\mathbb{E}^{3}'`` if
|
|
1580
|
+
``name`` is ``None`` and to ``name`` otherwise
|
|
1581
|
+
- ``coordinates`` -- (default: ``'Cartesian'``) string describing the type
|
|
1582
|
+
of coordinates to be initialized at the Euclidean 3-space creation;
|
|
1583
|
+
allowed values are ``'Cartesian'`` (see :meth:`cartesian_coordinates`),
|
|
1584
|
+
``'spherical'`` (see :meth:`spherical_coordinates`) and ``'cylindrical'``
|
|
1585
|
+
(see :meth:`cylindrical_coordinates`)
|
|
1586
|
+
- ``symbols`` -- (default: ``None``) string defining the coordinate text
|
|
1587
|
+
symbols and LaTeX symbols, with the same conventions as the argument
|
|
1588
|
+
``coordinates`` in
|
|
1589
|
+
:class:`~sage.manifolds.differentiable.chart.RealDiffChart`, namely
|
|
1590
|
+
``symbols`` is a string of coordinate fields separated by a blank space,
|
|
1591
|
+
where each field contains the coordinate's text symbol and possibly the
|
|
1592
|
+
coordinate's LaTeX symbol (when the latter is different from the text
|
|
1593
|
+
symbol), both symbols being separated by a colon (``:``); if ``None``,
|
|
1594
|
+
the symbols will be automatically generated according to the value of
|
|
1595
|
+
``coordinates``
|
|
1596
|
+
- ``metric_name`` -- (default: ``'g'``) string; name (symbol) given to the
|
|
1597
|
+
Euclidean metric tensor
|
|
1598
|
+
- ``metric_latex_name`` -- (default: ``None``) string; LaTeX symbol to
|
|
1599
|
+
denote the Euclidean metric tensor; if none is provided, it is set to
|
|
1600
|
+
``metric_name``
|
|
1601
|
+
- ``start_index`` -- (default: 1) integer; lower value of the range of
|
|
1602
|
+
indices used for "indexed objects" in the Euclidean 3-space, e.g.
|
|
1603
|
+
coordinates of a chart
|
|
1604
|
+
- ``base_manifold`` -- (default: ``None``) if not ``None``, must be a
|
|
1605
|
+
Euclidean 3-space; the created object is then an open subset of
|
|
1606
|
+
``base_manifold``
|
|
1607
|
+
- ``category`` -- (default: ``None``) to specify the category; if ``None``,
|
|
1608
|
+
``Manifolds(RR).Smooth() & MetricSpaces().Complete()`` is assumed
|
|
1609
|
+
- ``names`` -- (default: ``None``) unused argument, except if
|
|
1610
|
+
``symbols`` is not provided; it must then be a tuple containing
|
|
1611
|
+
the coordinate symbols (this is guaranteed if the shortcut operator
|
|
1612
|
+
``<,>`` is used)
|
|
1613
|
+
- ``init_coord_methods`` -- (default: ``None``) dictionary of methods
|
|
1614
|
+
to initialize the various type of coordinates, with each key being a
|
|
1615
|
+
string describing the type of coordinates; to be used by derived classes
|
|
1616
|
+
only
|
|
1617
|
+
- ``unique_tag`` -- (default: ``None``) tag used to force the construction
|
|
1618
|
+
of a new object when all the other arguments have been used previously
|
|
1619
|
+
(without ``unique_tag``, the
|
|
1620
|
+
:class:`~sage.structure.unique_representation.UniqueRepresentation`
|
|
1621
|
+
behavior inherited from
|
|
1622
|
+
:class:`~sage.manifolds.differentiable.pseudo_riemannian.PseudoRiemannianManifold`
|
|
1623
|
+
would return the previously constructed object corresponding to these
|
|
1624
|
+
arguments)
|
|
1625
|
+
|
|
1626
|
+
EXAMPLES:
|
|
1627
|
+
|
|
1628
|
+
A 3-dimensional Euclidean space::
|
|
1629
|
+
|
|
1630
|
+
sage: E = EuclideanSpace(3); E
|
|
1631
|
+
Euclidean space E^3
|
|
1632
|
+
sage: latex(E)
|
|
1633
|
+
\mathbb{E}^{3}
|
|
1634
|
+
|
|
1635
|
+
``E`` belongs to the class :class:`Euclidean3dimSpace` (actually to
|
|
1636
|
+
a dynamically generated subclass of it via SageMath's category framework)::
|
|
1637
|
+
|
|
1638
|
+
sage: type(E)
|
|
1639
|
+
<class 'sage.manifolds.differentiable.examples.euclidean.Euclidean3dimSpace_with_category'>
|
|
1640
|
+
|
|
1641
|
+
``E`` is both a real smooth manifold of dimension `3` and a complete metric
|
|
1642
|
+
space::
|
|
1643
|
+
|
|
1644
|
+
sage: E.category()
|
|
1645
|
+
Join of Category of smooth manifolds over Real Field with 53 bits of
|
|
1646
|
+
precision and Category of connected manifolds over Real Field with
|
|
1647
|
+
53 bits of precision and Category of complete metric spaces
|
|
1648
|
+
sage: dim(E)
|
|
1649
|
+
3
|
|
1650
|
+
|
|
1651
|
+
It is endowed with a default coordinate chart, which is that of Cartesian
|
|
1652
|
+
coordinates `(x,y,z)`::
|
|
1653
|
+
|
|
1654
|
+
sage: E.atlas()
|
|
1655
|
+
[Chart (E^3, (x, y, z))]
|
|
1656
|
+
sage: E.default_chart()
|
|
1657
|
+
Chart (E^3, (x, y, z))
|
|
1658
|
+
sage: cartesian = E.cartesian_coordinates()
|
|
1659
|
+
sage: cartesian is E.default_chart()
|
|
1660
|
+
True
|
|
1661
|
+
|
|
1662
|
+
A point of ``E``::
|
|
1663
|
+
|
|
1664
|
+
sage: p = E((3,-2,1)); p
|
|
1665
|
+
Point on the Euclidean space E^3
|
|
1666
|
+
sage: cartesian(p)
|
|
1667
|
+
(3, -2, 1)
|
|
1668
|
+
sage: p in E
|
|
1669
|
+
True
|
|
1670
|
+
sage: p.parent() is E
|
|
1671
|
+
True
|
|
1672
|
+
|
|
1673
|
+
``E`` is endowed with a default metric tensor, which defines the
|
|
1674
|
+
Euclidean scalar product::
|
|
1675
|
+
|
|
1676
|
+
sage: g = E.metric(); g
|
|
1677
|
+
Riemannian metric g on the Euclidean space E^3
|
|
1678
|
+
sage: g.display()
|
|
1679
|
+
g = dx⊗dx + dy⊗dy + dz⊗dz
|
|
1680
|
+
|
|
1681
|
+
Curvilinear coordinates can be introduced on ``E``: see
|
|
1682
|
+
:meth:`spherical_coordinates` and :meth:`cylindrical_coordinates`.
|
|
1683
|
+
|
|
1684
|
+
.. SEEALSO::
|
|
1685
|
+
|
|
1686
|
+
:ref:`EuclideanSpace_example2`
|
|
1687
|
+
"""
|
|
1688
|
+
def __init__(self, name=None, latex_name=None, coordinates='Cartesian',
|
|
1689
|
+
symbols=None, metric_name='g', metric_latex_name=None,
|
|
1690
|
+
start_index=1, base_manifold=None, category=None, unique_tag=None):
|
|
1691
|
+
r"""
|
|
1692
|
+
Construct a Euclidean 3-space.
|
|
1693
|
+
|
|
1694
|
+
TESTS::
|
|
1695
|
+
|
|
1696
|
+
sage: E = EuclideanSpace(3); E
|
|
1697
|
+
Euclidean space E^3
|
|
1698
|
+
sage: E.metric()
|
|
1699
|
+
Riemannian metric g on the Euclidean space E^3
|
|
1700
|
+
sage: TestSuite(E).run()
|
|
1701
|
+
"""
|
|
1702
|
+
if coordinates not in ['Cartesian', 'spherical', 'cylindrical']:
|
|
1703
|
+
raise TypeError("unknown coordinate type")
|
|
1704
|
+
if symbols is None:
|
|
1705
|
+
if coordinates == 'Cartesian':
|
|
1706
|
+
symbols = 'x y z'
|
|
1707
|
+
elif coordinates == 'spherical':
|
|
1708
|
+
symbols = 'r th:\\theta ph:\\phi'
|
|
1709
|
+
elif coordinates == 'cylindrical':
|
|
1710
|
+
symbols = 'r ph:\\phi z'
|
|
1711
|
+
self._spherical_chart = None # to be constructed later if necessary
|
|
1712
|
+
self._spherical_frame = None # orthonormal frame
|
|
1713
|
+
self._cylindrical_chart = None
|
|
1714
|
+
self._cylindrical_frame = None # orthonormal frame
|
|
1715
|
+
init_coord_methods = {'Cartesian': self._init_cartesian,
|
|
1716
|
+
'spherical': self._init_spherical,
|
|
1717
|
+
'cylindrical': self._init_cylindrical}
|
|
1718
|
+
EuclideanSpace.__init__(self, 3, name=name,
|
|
1719
|
+
latex_name=latex_name,
|
|
1720
|
+
coordinates=coordinates,
|
|
1721
|
+
symbols=symbols,
|
|
1722
|
+
metric_name=metric_name,
|
|
1723
|
+
metric_latex_name=metric_latex_name,
|
|
1724
|
+
start_index=start_index,
|
|
1725
|
+
base_manifold=base_manifold, category=category,
|
|
1726
|
+
init_coord_methods=init_coord_methods)
|
|
1727
|
+
if coordinates == 'spherical':
|
|
1728
|
+
# The default frame is the spherical coordinate frame; we change it
|
|
1729
|
+
# to the orthonormal spherical frame
|
|
1730
|
+
self.set_default_frame(self.spherical_frame())
|
|
1731
|
+
if coordinates == 'cylindrical':
|
|
1732
|
+
# The default frame is the cylindrical coordinate frame; we change
|
|
1733
|
+
# it to the orthonormal cylindrical frame
|
|
1734
|
+
self.set_default_frame(self.cylindrical_frame())
|
|
1735
|
+
|
|
1736
|
+
def _repr_(self):
|
|
1737
|
+
r"""
|
|
1738
|
+
Return a string representation of ``self``.
|
|
1739
|
+
|
|
1740
|
+
TESTS::
|
|
1741
|
+
|
|
1742
|
+
sage: E = EuclideanSpace(3)
|
|
1743
|
+
sage: E._repr_()
|
|
1744
|
+
'Euclidean space E^3'
|
|
1745
|
+
sage: E # indirect doctest
|
|
1746
|
+
Euclidean space E^3
|
|
1747
|
+
sage: E = EuclideanSpace(3, name='E')
|
|
1748
|
+
sage: E._repr_()
|
|
1749
|
+
'Euclidean space E'
|
|
1750
|
+
"""
|
|
1751
|
+
return "Euclidean space {}".format(self._name)
|
|
1752
|
+
|
|
1753
|
+
def _init_spherical(self, symbols):
|
|
1754
|
+
r"""
|
|
1755
|
+
Construct the chart of spherical coordinates and initialize the
|
|
1756
|
+
components of the metric tensor in it.
|
|
1757
|
+
|
|
1758
|
+
TESTS::
|
|
1759
|
+
|
|
1760
|
+
sage: E = EuclideanSpace(3)
|
|
1761
|
+
sage: E.atlas()
|
|
1762
|
+
[Chart (E^3, (x, y, z))]
|
|
1763
|
+
sage: E._init_spherical(r"R Th:\Theta Ph:\Phi")
|
|
1764
|
+
sage: E.atlas()
|
|
1765
|
+
[Chart (E^3, (x, y, z)), Chart (E^3, (R, Th, Ph))]
|
|
1766
|
+
"""
|
|
1767
|
+
coords = symbols.split() # list of strings, one per coordinate
|
|
1768
|
+
# Adding the coordinate ranges:
|
|
1769
|
+
coordinates = (coords[0] + ':(0,+oo) ' + coords[1] + ':(0,pi) '
|
|
1770
|
+
+ coords[2] + ':(0,2*pi):periodic')
|
|
1771
|
+
chart = self.chart(coordinates=coordinates)
|
|
1772
|
+
self._spherical_chart = chart
|
|
1773
|
+
frame = chart.frame()
|
|
1774
|
+
# Initialization of the metric components and the associated
|
|
1775
|
+
# Christoffel symbols
|
|
1776
|
+
g = self.metric()
|
|
1777
|
+
gc = g.add_comp(frame)
|
|
1778
|
+
i1 = self._sindex
|
|
1779
|
+
i2 = i1 + 1
|
|
1780
|
+
i3 = i1 + 2
|
|
1781
|
+
r, th, ph = chart[:]
|
|
1782
|
+
gc[i1, i1, chart] = 1
|
|
1783
|
+
gc[i2, i2, chart] = r**2
|
|
1784
|
+
gc[i3, i3, chart] = (r*sin(th))**2
|
|
1785
|
+
# Orthonormal frame associated with spherical coordinates:
|
|
1786
|
+
to_orthonormal = self.automorphism_field()
|
|
1787
|
+
to_orthonormal[frame, i1, i1, chart] = 1
|
|
1788
|
+
to_orthonormal[frame, i2, i2, chart] = 1/r
|
|
1789
|
+
to_orthonormal[frame, i3, i3, chart] = 1/(r*sin(th))
|
|
1790
|
+
oframe = frame.new_frame(to_orthonormal, 'e',
|
|
1791
|
+
indices=(str(r), str(th), str(ph)),
|
|
1792
|
+
latex_indices=(latex(r), latex(th), latex(ph)))
|
|
1793
|
+
self._spherical_frame = oframe
|
|
1794
|
+
g.comp(oframe)
|
|
1795
|
+
|
|
1796
|
+
def _init_cylindrical(self, symbols):
|
|
1797
|
+
r"""
|
|
1798
|
+
Construct the chart of cylindrical coordinates and initialize the
|
|
1799
|
+
components of the metric tensor in it.
|
|
1800
|
+
|
|
1801
|
+
TESTS::
|
|
1802
|
+
|
|
1803
|
+
sage: E = EuclideanSpace(3)
|
|
1804
|
+
sage: E.atlas()
|
|
1805
|
+
[Chart (E^3, (x, y, z))]
|
|
1806
|
+
sage: E._init_cylindrical(r"r ph:\phi z")
|
|
1807
|
+
sage: E.atlas()
|
|
1808
|
+
[Chart (E^3, (x, y, z)), Chart (E^3, (r, ph, z))]
|
|
1809
|
+
"""
|
|
1810
|
+
coords = symbols.split() # list of strings, one per coordinate
|
|
1811
|
+
# Adding the coordinate ranges:
|
|
1812
|
+
coordinates = (coords[0] + ':(0,+oo) ' + coords[1]
|
|
1813
|
+
+ ':(0,2*pi):periodic ' + coords[2])
|
|
1814
|
+
chart = self.chart(coordinates=coordinates)
|
|
1815
|
+
self._cylindrical_chart = chart
|
|
1816
|
+
frame = chart.frame()
|
|
1817
|
+
# Initialization of the metric components and the associated
|
|
1818
|
+
# Christoffel symbols
|
|
1819
|
+
g = self.metric()
|
|
1820
|
+
gc = g.add_comp(frame)
|
|
1821
|
+
i1 = self._sindex
|
|
1822
|
+
i2 = i1 + 1
|
|
1823
|
+
i3 = i1 + 2
|
|
1824
|
+
rh, ph, z = chart[:]
|
|
1825
|
+
gc[i1, i1, chart] = 1
|
|
1826
|
+
gc[i2, i2, chart] = rh**2
|
|
1827
|
+
gc[i3, i3, chart] = 1
|
|
1828
|
+
# Orthonormal frame associated with cylindrical coordinates:
|
|
1829
|
+
to_orthonormal = self.automorphism_field()
|
|
1830
|
+
to_orthonormal[frame, i1, i1, chart] = 1
|
|
1831
|
+
to_orthonormal[frame, i2, i2, chart] = 1 / rh
|
|
1832
|
+
to_orthonormal[frame, i3, i3, chart] = 1
|
|
1833
|
+
oframe = frame.new_frame(to_orthonormal, 'e',
|
|
1834
|
+
indices=(str(rh), str(ph), str(z)),
|
|
1835
|
+
latex_indices=(latex(rh), latex(ph), latex(z)))
|
|
1836
|
+
self._cylindrical_frame = oframe
|
|
1837
|
+
g.comp(oframe)
|
|
1838
|
+
|
|
1839
|
+
def _transition_spherical_cartesian(self):
|
|
1840
|
+
r"""
|
|
1841
|
+
Transitions between spherical and Cartesian coordinates.
|
|
1842
|
+
|
|
1843
|
+
TESTS::
|
|
1844
|
+
|
|
1845
|
+
sage: E = EuclideanSpace(3)
|
|
1846
|
+
sage: E._init_spherical(r"r th:\theta ph:\phi")
|
|
1847
|
+
sage: E.atlas()
|
|
1848
|
+
[Chart (E^3, (x, y, z)), Chart (E^3, (r, th, ph))]
|
|
1849
|
+
sage: E.coord_changes() # no transition map has been defined yet
|
|
1850
|
+
{}
|
|
1851
|
+
sage: E._transition_spherical_cartesian() # long time
|
|
1852
|
+
|
|
1853
|
+
2 transition maps have been created::
|
|
1854
|
+
|
|
1855
|
+
sage: len(E.coord_changes()) # long time
|
|
1856
|
+
2
|
|
1857
|
+
|
|
1858
|
+
Tests of the change-of-frame formulas::
|
|
1859
|
+
|
|
1860
|
+
sage: # long time
|
|
1861
|
+
sage: spher = E.spherical_coordinates()
|
|
1862
|
+
sage: spher_f = E.spherical_frame()
|
|
1863
|
+
sage: cart_f = E.cartesian_frame()
|
|
1864
|
+
sage: E.change_of_frame(cart_f, spher_f)[:,spher]
|
|
1865
|
+
[cos(ph)*sin(th) cos(ph)*cos(th) -sin(ph)]
|
|
1866
|
+
[sin(ph)*sin(th) cos(th)*sin(ph) cos(ph)]
|
|
1867
|
+
[ cos(th) -sin(th) 0]
|
|
1868
|
+
sage: E.change_of_frame(spher_f, cart_f)[:,spher]
|
|
1869
|
+
[cos(ph)*sin(th) sin(ph)*sin(th) cos(th)]
|
|
1870
|
+
[cos(ph)*cos(th) cos(th)*sin(ph) -sin(th)]
|
|
1871
|
+
[ -sin(ph) cos(ph) 0]
|
|
1872
|
+
"""
|
|
1873
|
+
# Transition maps spherical chart <-> Cartesian chart
|
|
1874
|
+
chart_cart = self._cartesian_chart
|
|
1875
|
+
chart_spher = self._spherical_chart
|
|
1876
|
+
x, y, z = chart_cart[:]
|
|
1877
|
+
r, th, ph = chart_spher[:]
|
|
1878
|
+
spher_to_cart = chart_spher.transition_map(chart_cart,
|
|
1879
|
+
[r*sin(th)*cos(ph), r*sin(th)*sin(ph), r*cos(th)])
|
|
1880
|
+
spher_to_cart.set_inverse(sqrt(x**2+y**2+z**2),
|
|
1881
|
+
atan2(sqrt(x**2+y**2),z), atan2(y, x),
|
|
1882
|
+
check=False)
|
|
1883
|
+
# Automorphism Cartesian frame → orthonormal spherical frame:
|
|
1884
|
+
oframe = self._spherical_frame
|
|
1885
|
+
cframe = chart_cart.frame()
|
|
1886
|
+
sframe = chart_spher.frame()
|
|
1887
|
+
chg = self._frame_changes
|
|
1888
|
+
cframe_to_oframe = chg[(sframe, oframe)] * chg[(cframe, sframe)]
|
|
1889
|
+
# cframe_to_oframe has been computed only in sframe;
|
|
1890
|
+
# its components in oframe are computed by
|
|
1891
|
+
cmp_of = cframe_to_oframe.comp(oframe)
|
|
1892
|
+
# while its components in cframe are obtained by identifying the
|
|
1893
|
+
# matrices in cframe and oframe:
|
|
1894
|
+
cmp_cf = cframe_to_oframe.add_comp(cframe)
|
|
1895
|
+
for i in self.irange():
|
|
1896
|
+
for j in self.irange():
|
|
1897
|
+
cmp_cf[[i,j]] = cmp_of[[i,j]]
|
|
1898
|
+
# Automorphism orthonormal spherical frame → Cartesian frame:
|
|
1899
|
+
oframe_to_cframe = chg[(sframe, cframe)] * chg[(oframe, sframe)]
|
|
1900
|
+
# oframe_to_cframe has been computed only in sframe;
|
|
1901
|
+
# its components in oframe are computed by
|
|
1902
|
+
cmp_of = oframe_to_cframe.comp(oframe)
|
|
1903
|
+
# while its components in cframe are obtained by identifying the
|
|
1904
|
+
# matrices in cframe and oframe:
|
|
1905
|
+
cmp_cf = oframe_to_cframe.add_comp(cframe)
|
|
1906
|
+
for i in self.irange():
|
|
1907
|
+
for j in self.irange():
|
|
1908
|
+
cmp_cf[[i,j]] = cmp_of[[i,j]]
|
|
1909
|
+
# Storage of the results:
|
|
1910
|
+
chg[(cframe, oframe)] = cframe_to_oframe
|
|
1911
|
+
chg[(oframe, cframe)] = oframe_to_cframe
|
|
1912
|
+
vmodule = self.vector_field_module()
|
|
1913
|
+
vmodule.set_change_of_basis(cframe, oframe, cframe_to_oframe,
|
|
1914
|
+
compute_inverse=False)
|
|
1915
|
+
vmodule.set_change_of_basis(oframe, cframe, oframe_to_cframe,
|
|
1916
|
+
compute_inverse=False)
|
|
1917
|
+
|
|
1918
|
+
def _transition_cylindrical_cartesian(self):
|
|
1919
|
+
r"""
|
|
1920
|
+
Transitions between cylindrical and Cartesian coordinates.
|
|
1921
|
+
|
|
1922
|
+
TESTS::
|
|
1923
|
+
|
|
1924
|
+
sage: E = EuclideanSpace(3)
|
|
1925
|
+
sage: E._init_cylindrical(r"r ph:\phi z")
|
|
1926
|
+
sage: E.atlas()
|
|
1927
|
+
[Chart (E^3, (x, y, z)), Chart (E^3, (r, ph, z))]
|
|
1928
|
+
sage: E.coord_changes() # no transition map has been defined yet
|
|
1929
|
+
{}
|
|
1930
|
+
sage: E._transition_cylindrical_cartesian() # long time
|
|
1931
|
+
|
|
1932
|
+
2 transition maps have been created::
|
|
1933
|
+
|
|
1934
|
+
sage: len(E.coord_changes()) # long time
|
|
1935
|
+
2
|
|
1936
|
+
|
|
1937
|
+
Tests of the change-of-frame formulas::
|
|
1938
|
+
|
|
1939
|
+
sage: # long time
|
|
1940
|
+
sage: cylind = E.cylindrical_coordinates()
|
|
1941
|
+
sage: cylind_f = E.cylindrical_frame()
|
|
1942
|
+
sage: cart_f= E.cartesian_frame()
|
|
1943
|
+
sage: E.change_of_frame(cart_f, cylind_f)[:,cylind]
|
|
1944
|
+
[ cos(ph) -sin(ph) 0]
|
|
1945
|
+
[ sin(ph) cos(ph) 0]
|
|
1946
|
+
[ 0 0 1]
|
|
1947
|
+
sage: E.change_of_frame(cylind_f, cart_f)[:,cylind]
|
|
1948
|
+
[ cos(ph) sin(ph) 0]
|
|
1949
|
+
[-sin(ph) cos(ph) 0]
|
|
1950
|
+
[ 0 0 1]
|
|
1951
|
+
"""
|
|
1952
|
+
# Transition maps cylindrical chart <-> Cartesian chart
|
|
1953
|
+
chart_cart = self._cartesian_chart
|
|
1954
|
+
chart_cylind = self._cylindrical_chart
|
|
1955
|
+
x, y, z = chart_cart[:]
|
|
1956
|
+
rh, ph, z = chart_cylind[:]
|
|
1957
|
+
cylind_to_cart = chart_cylind.transition_map(chart_cart,
|
|
1958
|
+
[rh*cos(ph), rh*sin(ph), z])
|
|
1959
|
+
cylind_to_cart.set_inverse(sqrt(x**2+y**2), atan2(y, x), z, check=False)
|
|
1960
|
+
# Automorphism Cartesian frame → orthonormal cylindrical frame:
|
|
1961
|
+
oframe = self._cylindrical_frame
|
|
1962
|
+
cframe = chart_cart.frame()
|
|
1963
|
+
sframe = chart_cylind.frame()
|
|
1964
|
+
chg = self._frame_changes
|
|
1965
|
+
cframe_to_oframe = chg[(sframe, oframe)] * chg[(cframe, sframe)]
|
|
1966
|
+
# cframe_to_oframe has been computed only in sframe;
|
|
1967
|
+
# its components in oframe are computed by
|
|
1968
|
+
cmp_of = cframe_to_oframe.comp(oframe)
|
|
1969
|
+
# while its components in cframe are obtained by identifying the
|
|
1970
|
+
# matrices in cframe and oframe:
|
|
1971
|
+
cmp_cf = cframe_to_oframe.add_comp(cframe)
|
|
1972
|
+
for i in self.irange():
|
|
1973
|
+
for j in self.irange():
|
|
1974
|
+
cmp_cf[[i,j]] = cmp_of[[i,j]]
|
|
1975
|
+
# Automorphism orthonormal cylindrical frame → Cartesian frame:
|
|
1976
|
+
oframe_to_cframe = chg[(sframe, cframe)] * chg[(oframe, sframe)]
|
|
1977
|
+
# oframe_to_cframe has been computed only in sframe;
|
|
1978
|
+
# its components in oframe are computed by
|
|
1979
|
+
cmp_of = oframe_to_cframe.comp(oframe)
|
|
1980
|
+
# while its components in cframe are obtained by identifying the
|
|
1981
|
+
# matrices in cframe and oframe:
|
|
1982
|
+
cmp_cf = oframe_to_cframe.add_comp(cframe)
|
|
1983
|
+
for i in self.irange():
|
|
1984
|
+
for j in self.irange():
|
|
1985
|
+
cmp_cf[[i,j]] = cmp_of[[i,j]]
|
|
1986
|
+
# Storage of the results:
|
|
1987
|
+
chg[(cframe, oframe)] = cframe_to_oframe
|
|
1988
|
+
chg[(oframe, cframe)] = oframe_to_cframe
|
|
1989
|
+
vmodule = self.vector_field_module()
|
|
1990
|
+
vmodule.set_change_of_basis(cframe, oframe, cframe_to_oframe,
|
|
1991
|
+
compute_inverse=False)
|
|
1992
|
+
vmodule.set_change_of_basis(oframe, cframe, oframe_to_cframe,
|
|
1993
|
+
compute_inverse=False)
|
|
1994
|
+
|
|
1995
|
+
def _transition_spherical_cylindrical(self):
|
|
1996
|
+
r"""
|
|
1997
|
+
Transitions between spherical and cylindrical coordinates.
|
|
1998
|
+
|
|
1999
|
+
TESTS::
|
|
2000
|
+
|
|
2001
|
+
sage: E = EuclideanSpace(3, coordinates='cylindrical')
|
|
2002
|
+
sage: E._init_spherical(r"r th:\theta ph:\phi")
|
|
2003
|
+
sage: E.atlas()
|
|
2004
|
+
[Chart (E^3, (r, ph, z)), Chart (E^3, (r, th, ph))]
|
|
2005
|
+
sage: E.coord_changes() # no transition map has been defined yet
|
|
2006
|
+
{}
|
|
2007
|
+
sage: E._transition_spherical_cylindrical() # long time
|
|
2008
|
+
|
|
2009
|
+
2 transition maps have been created::
|
|
2010
|
+
|
|
2011
|
+
sage: len(E.coord_changes()) # long time
|
|
2012
|
+
2
|
|
2013
|
+
|
|
2014
|
+
Tests of the change-of-frame formulas::
|
|
2015
|
+
|
|
2016
|
+
sage: # long time
|
|
2017
|
+
sage: spher = E.spherical_coordinates()
|
|
2018
|
+
sage: spher_f = E.spherical_frame()
|
|
2019
|
+
sage: cylind_f = E.cylindrical_frame()
|
|
2020
|
+
sage: E.change_of_frame(cylind_f, spher_f)[:, spher]
|
|
2021
|
+
[ sin(th) cos(th) 0]
|
|
2022
|
+
[ 0 0 1]
|
|
2023
|
+
[ cos(th) -sin(th) 0]
|
|
2024
|
+
sage: E.change_of_frame(spher_f, cylind_f)[:, spher]
|
|
2025
|
+
[ sin(th) 0 cos(th)]
|
|
2026
|
+
[ cos(th) 0 -sin(th)]
|
|
2027
|
+
[ 0 1 0]
|
|
2028
|
+
"""
|
|
2029
|
+
# Transition maps spherical chart <-> cylindrical chart
|
|
2030
|
+
cylind = self._cylindrical_chart
|
|
2031
|
+
spher = self._spherical_chart
|
|
2032
|
+
rh, ph, z = cylind[:]
|
|
2033
|
+
r, th, ph = spher[:]
|
|
2034
|
+
spher_to_cylind = spher.transition_map(cylind,
|
|
2035
|
+
[r*sin(th), ph, r*cos(th)])
|
|
2036
|
+
spher_to_cylind.set_inverse(sqrt(rh**2 + z**2), atan2(rh,z), ph,
|
|
2037
|
+
check=False)
|
|
2038
|
+
# Automorphism orthon. cylindrical frame -> orthon. spherical frame
|
|
2039
|
+
cf = cylind.frame() # coordinate cylindrical frame
|
|
2040
|
+
sf = spher.frame() # coordinate spherical frame
|
|
2041
|
+
ocf = self._cylindrical_frame # orthonormal cylindrical frame
|
|
2042
|
+
osf = self._spherical_frame # orthonormal spherical frame
|
|
2043
|
+
chg = self._frame_changes
|
|
2044
|
+
oc_to_os = chg[(sf, osf)] * chg[(cf, sf)] * chg[(ocf, cf)]
|
|
2045
|
+
# oc_to_os has been computed only in sf frame; its components in osf
|
|
2046
|
+
# frame are computed by:
|
|
2047
|
+
cmp_osf = oc_to_os.comp(osf)
|
|
2048
|
+
# while its components in ocf frame are obtained by identifying the
|
|
2049
|
+
# matrices in ocf frame and osf oframe:
|
|
2050
|
+
cmp_ocf = oc_to_os.add_comp(ocf)
|
|
2051
|
+
for i in self.irange():
|
|
2052
|
+
for j in self.irange():
|
|
2053
|
+
cmp_ocf[[i,j]] = cmp_osf[[i,j]]
|
|
2054
|
+
# Automorphism orthon. spherical frame -> orthon. cylindrical frame
|
|
2055
|
+
os_to_oc = chg[(cf, ocf)] * chg[(sf, cf)] * chg[(osf, sf)]
|
|
2056
|
+
# oc_to_os has been computed only in cf frame; its components in ocf
|
|
2057
|
+
# frame are computed by
|
|
2058
|
+
cmp_ocf = os_to_oc.comp(ocf)
|
|
2059
|
+
# while its components in osf frame are obtained by identifying the
|
|
2060
|
+
# matrices in osf frame and ocf oframe:
|
|
2061
|
+
cmp_osf = os_to_oc.add_comp(osf)
|
|
2062
|
+
for i in self.irange():
|
|
2063
|
+
for j in self.irange():
|
|
2064
|
+
cmp_osf[[i,j]] = cmp_ocf[[i,j]]
|
|
2065
|
+
# Storage of the results:
|
|
2066
|
+
chg[(ocf, osf)] = oc_to_os
|
|
2067
|
+
chg[(osf, ocf)] = os_to_oc
|
|
2068
|
+
vmodule = self.vector_field_module()
|
|
2069
|
+
vmodule.set_change_of_basis(ocf, osf, oc_to_os, compute_inverse=False)
|
|
2070
|
+
vmodule.set_change_of_basis(osf, ocf, os_to_oc, compute_inverse=False)
|
|
2071
|
+
|
|
2072
|
+
def cartesian_coordinates(self, symbols=None, names=None):
|
|
2073
|
+
r"""
|
|
2074
|
+
Return the chart of Cartesian coordinates, possibly creating it if it
|
|
2075
|
+
does not already exist.
|
|
2076
|
+
|
|
2077
|
+
INPUT:
|
|
2078
|
+
|
|
2079
|
+
- ``symbols`` -- (default: ``None``) string defining the coordinate
|
|
2080
|
+
text symbols and LaTeX symbols, with the same conventions as the
|
|
2081
|
+
argument ``coordinates`` in
|
|
2082
|
+
:class:`~sage.manifolds.differentiable.chart.RealDiffChart`; this is
|
|
2083
|
+
used only if the Cartesian chart has not been already defined; if
|
|
2084
|
+
``None`` the symbols are generated as `(x,y,z)`.
|
|
2085
|
+
- ``names`` -- (default: ``None``) unused argument, except if
|
|
2086
|
+
``symbols`` is not provided; it must be a tuple containing
|
|
2087
|
+
the coordinate symbols (this is guaranteed if the shortcut operator
|
|
2088
|
+
``<,>`` is used)
|
|
2089
|
+
|
|
2090
|
+
OUTPUT:
|
|
2091
|
+
|
|
2092
|
+
- the chart of Cartesian coordinates, as an instance of
|
|
2093
|
+
:class:`~sage.manifolds.differentiable.chart.RealDiffChart`
|
|
2094
|
+
|
|
2095
|
+
EXAMPLES::
|
|
2096
|
+
|
|
2097
|
+
sage: E = EuclideanSpace(3)
|
|
2098
|
+
sage: E.cartesian_coordinates()
|
|
2099
|
+
Chart (E^3, (x, y, z))
|
|
2100
|
+
sage: E.cartesian_coordinates().coord_range()
|
|
2101
|
+
x: (-oo, +oo); y: (-oo, +oo); z: (-oo, +oo)
|
|
2102
|
+
|
|
2103
|
+
An example where the Cartesian coordinates have not been previously
|
|
2104
|
+
created::
|
|
2105
|
+
|
|
2106
|
+
sage: E = EuclideanSpace(3, coordinates='spherical')
|
|
2107
|
+
sage: E.atlas() # only spherical coordinates have been initialized
|
|
2108
|
+
[Chart (E^3, (r, th, ph))]
|
|
2109
|
+
sage: E.cartesian_coordinates(symbols='X Y Z')
|
|
2110
|
+
Chart (E^3, (X, Y, Z))
|
|
2111
|
+
sage: E.atlas() # the Cartesian chart has been added to the atlas
|
|
2112
|
+
[Chart (E^3, (r, th, ph)), Chart (E^3, (X, Y, Z))]
|
|
2113
|
+
|
|
2114
|
+
The coordinate variables are returned by the square bracket operator::
|
|
2115
|
+
|
|
2116
|
+
sage: E.cartesian_coordinates()[1]
|
|
2117
|
+
X
|
|
2118
|
+
sage: E.cartesian_coordinates()[3]
|
|
2119
|
+
Z
|
|
2120
|
+
sage: E.cartesian_coordinates()[:]
|
|
2121
|
+
(X, Y, Z)
|
|
2122
|
+
|
|
2123
|
+
It is also possible to use the operator ``<,>`` to set symbolic
|
|
2124
|
+
variable containing the coordinates::
|
|
2125
|
+
|
|
2126
|
+
sage: E = EuclideanSpace(3, coordinates='spherical')
|
|
2127
|
+
sage: cartesian.<u,v,w> = E.cartesian_coordinates()
|
|
2128
|
+
sage: cartesian
|
|
2129
|
+
Chart (E^3, (u, v, w))
|
|
2130
|
+
sage: u, v, w
|
|
2131
|
+
(u, v, w)
|
|
2132
|
+
|
|
2133
|
+
The command ``cartesian.<u,v,w> = E.cartesian_coordinates()``
|
|
2134
|
+
is actually a shortcut for::
|
|
2135
|
+
|
|
2136
|
+
sage: cartesian = E.cartesian_coordinates(symbols='u v w')
|
|
2137
|
+
sage: u, v, w = cartesian[:]
|
|
2138
|
+
"""
|
|
2139
|
+
if self._cartesian_chart is None:
|
|
2140
|
+
if symbols is None:
|
|
2141
|
+
if names is None:
|
|
2142
|
+
symbols = 'x y z'
|
|
2143
|
+
else:
|
|
2144
|
+
symbols = names[0] + ' ' + names[1] + ' ' + names[2]
|
|
2145
|
+
self._init_cartesian(symbols)
|
|
2146
|
+
if self._spherical_chart:
|
|
2147
|
+
self._transition_spherical_cartesian()
|
|
2148
|
+
if self._cylindrical_chart:
|
|
2149
|
+
self._transition_cylindrical_cartesian()
|
|
2150
|
+
return self._cartesian_chart
|
|
2151
|
+
|
|
2152
|
+
def spherical_coordinates(self, symbols=None, names=None):
|
|
2153
|
+
r"""
|
|
2154
|
+
Return the chart of spherical coordinates, possibly creating it if it
|
|
2155
|
+
does not already exist.
|
|
2156
|
+
|
|
2157
|
+
INPUT:
|
|
2158
|
+
|
|
2159
|
+
- ``symbols`` -- (default: ``None``) string defining the coordinate
|
|
2160
|
+
text symbols and LaTeX symbols, with the same conventions as the
|
|
2161
|
+
argument ``coordinates`` in
|
|
2162
|
+
:class:`~sage.manifolds.differentiable.chart.RealDiffChart`; this is
|
|
2163
|
+
used only if the spherical chart has not been already defined; if
|
|
2164
|
+
``None`` the symbols are generated as `(r,\theta,\phi)`.
|
|
2165
|
+
- ``names`` -- (default: ``None``) unused argument, except if
|
|
2166
|
+
``symbols`` is not provided; it must be a tuple containing
|
|
2167
|
+
the coordinate symbols (this is guaranteed if the shortcut operator
|
|
2168
|
+
``<,>`` is used)
|
|
2169
|
+
|
|
2170
|
+
OUTPUT:
|
|
2171
|
+
|
|
2172
|
+
- the chart of spherical coordinates, as an instance of
|
|
2173
|
+
:class:`~sage.manifolds.differentiable.chart.RealDiffChart`
|
|
2174
|
+
|
|
2175
|
+
EXAMPLES::
|
|
2176
|
+
|
|
2177
|
+
sage: E = EuclideanSpace(3)
|
|
2178
|
+
sage: E.spherical_coordinates()
|
|
2179
|
+
Chart (E^3, (r, th, ph))
|
|
2180
|
+
sage: latex(_)
|
|
2181
|
+
\left(\mathbb{E}^{3},(r, {\theta}, {\phi})\right)
|
|
2182
|
+
sage: E.spherical_coordinates().coord_range()
|
|
2183
|
+
r: (0, +oo); th: (0, pi); ph: [0, 2*pi] (periodic)
|
|
2184
|
+
|
|
2185
|
+
The relation to Cartesian coordinates is::
|
|
2186
|
+
|
|
2187
|
+
sage: E.coord_change(E.spherical_coordinates(),
|
|
2188
|
+
....: E.cartesian_coordinates()).display()
|
|
2189
|
+
x = r*cos(ph)*sin(th)
|
|
2190
|
+
y = r*sin(ph)*sin(th)
|
|
2191
|
+
z = r*cos(th)
|
|
2192
|
+
sage: E.coord_change(E.cartesian_coordinates(),
|
|
2193
|
+
....: E.spherical_coordinates()).display()
|
|
2194
|
+
r = sqrt(x^2 + y^2 + z^2)
|
|
2195
|
+
th = arctan2(sqrt(x^2 + y^2), z)
|
|
2196
|
+
ph = arctan2(y, x)
|
|
2197
|
+
|
|
2198
|
+
The coordinate variables are returned by the square bracket operator::
|
|
2199
|
+
|
|
2200
|
+
sage: E.spherical_coordinates()[1]
|
|
2201
|
+
r
|
|
2202
|
+
sage: E.spherical_coordinates()[3]
|
|
2203
|
+
ph
|
|
2204
|
+
sage: E.spherical_coordinates()[:]
|
|
2205
|
+
(r, th, ph)
|
|
2206
|
+
|
|
2207
|
+
They can also be obtained via the operator ``<,>``::
|
|
2208
|
+
|
|
2209
|
+
sage: spherical.<r,th,ph> = E.spherical_coordinates()
|
|
2210
|
+
sage: spherical
|
|
2211
|
+
Chart (E^3, (r, th, ph))
|
|
2212
|
+
sage: r, th, ph
|
|
2213
|
+
(r, th, ph)
|
|
2214
|
+
|
|
2215
|
+
Actually, ``spherical.<r,th,ph> = E.spherical_coordinates()`` is a
|
|
2216
|
+
shortcut for::
|
|
2217
|
+
|
|
2218
|
+
sage: spherical = E.spherical_coordinates()
|
|
2219
|
+
sage: r, th, ph = spherical[:]
|
|
2220
|
+
|
|
2221
|
+
The coordinate symbols can be customized::
|
|
2222
|
+
|
|
2223
|
+
sage: E = EuclideanSpace(3)
|
|
2224
|
+
sage: E.spherical_coordinates(symbols=r"R T:\Theta F:\Phi")
|
|
2225
|
+
Chart (E^3, (R, T, F))
|
|
2226
|
+
sage: latex(E.spherical_coordinates())
|
|
2227
|
+
\left(\mathbb{E}^{3},(R, {\Theta}, {\Phi})\right)
|
|
2228
|
+
|
|
2229
|
+
Note that if the spherical coordinates have been already initialized,
|
|
2230
|
+
the argument ``symbols`` has no effect::
|
|
2231
|
+
|
|
2232
|
+
sage: E.spherical_coordinates(symbols=r"r th:\theta ph:\phi")
|
|
2233
|
+
Chart (E^3, (R, T, F))
|
|
2234
|
+
"""
|
|
2235
|
+
if self._spherical_chart is None:
|
|
2236
|
+
if symbols is None:
|
|
2237
|
+
if names is None:
|
|
2238
|
+
symbols = 'r th:\\theta ph:\\phi'
|
|
2239
|
+
else:
|
|
2240
|
+
names = list(names)
|
|
2241
|
+
if names[1] in ['t', 'th', 'theta']:
|
|
2242
|
+
names[1] = names[1] + ':\\theta'
|
|
2243
|
+
if names[2] in ['p', 'ph', 'phi']:
|
|
2244
|
+
names[2] = names[2] + ':\\phi'
|
|
2245
|
+
symbols = names[0] + ' ' + names[1] + ' ' + names[2]
|
|
2246
|
+
self._init_spherical(symbols)
|
|
2247
|
+
if self._cartesian_chart:
|
|
2248
|
+
self._transition_spherical_cartesian()
|
|
2249
|
+
if self._cylindrical_chart:
|
|
2250
|
+
self._transition_spherical_cylindrical()
|
|
2251
|
+
return self._spherical_chart
|
|
2252
|
+
|
|
2253
|
+
def spherical_frame(self):
|
|
2254
|
+
r"""
|
|
2255
|
+
Return the orthonormal vector frame associated with spherical
|
|
2256
|
+
coordinates.
|
|
2257
|
+
|
|
2258
|
+
OUTPUT: :class:`~sage.manifolds.differentiable.vectorframe.VectorFrame`
|
|
2259
|
+
|
|
2260
|
+
EXAMPLES::
|
|
2261
|
+
|
|
2262
|
+
sage: E = EuclideanSpace(3)
|
|
2263
|
+
sage: E.spherical_frame()
|
|
2264
|
+
Vector frame (E^3, (e_r,e_th,e_ph))
|
|
2265
|
+
sage: E.spherical_frame()[1]
|
|
2266
|
+
Vector field e_r on the Euclidean space E^3
|
|
2267
|
+
sage: E.spherical_frame()[:]
|
|
2268
|
+
(Vector field e_r on the Euclidean space E^3,
|
|
2269
|
+
Vector field e_th on the Euclidean space E^3,
|
|
2270
|
+
Vector field e_ph on the Euclidean space E^3)
|
|
2271
|
+
|
|
2272
|
+
The spherical frame expressed in terms of the Cartesian one::
|
|
2273
|
+
|
|
2274
|
+
sage: for e in E.spherical_frame():
|
|
2275
|
+
....: e.display(E.cartesian_frame(), E.spherical_coordinates())
|
|
2276
|
+
e_r = cos(ph)*sin(th) e_x + sin(ph)*sin(th) e_y + cos(th) e_z
|
|
2277
|
+
e_th = cos(ph)*cos(th) e_x + cos(th)*sin(ph) e_y - sin(th) e_z
|
|
2278
|
+
e_ph = -sin(ph) e_x + cos(ph) e_y
|
|
2279
|
+
|
|
2280
|
+
The orthonormal frame `(e_r, e_\theta, e_\phi)` expressed in terms of
|
|
2281
|
+
the coordinate frame
|
|
2282
|
+
`\left(\frac{\partial}{\partial r}, \frac{\partial}{\partial\theta},
|
|
2283
|
+
\frac{\partial}{\partial\phi}\right)`::
|
|
2284
|
+
|
|
2285
|
+
sage: for e in E.spherical_frame():
|
|
2286
|
+
....: e.display(E.spherical_coordinates())
|
|
2287
|
+
e_r = ∂/∂r
|
|
2288
|
+
e_th = 1/r ∂/∂th
|
|
2289
|
+
e_ph = 1/(r*sin(th)) ∂/∂ph
|
|
2290
|
+
"""
|
|
2291
|
+
if self._spherical_frame is None:
|
|
2292
|
+
# create the spherical chart and the associated orthonormal frame
|
|
2293
|
+
self.spherical_coordinates()
|
|
2294
|
+
return self._spherical_frame
|
|
2295
|
+
|
|
2296
|
+
def cylindrical_coordinates(self, symbols=None, names=None):
|
|
2297
|
+
r"""
|
|
2298
|
+
Return the chart of cylindrical coordinates, possibly creating it if it
|
|
2299
|
+
does not already exist.
|
|
2300
|
+
|
|
2301
|
+
INPUT:
|
|
2302
|
+
|
|
2303
|
+
- ``symbols`` -- (default: ``None``) string defining the coordinate
|
|
2304
|
+
text symbols and LaTeX symbols, with the same conventions as the
|
|
2305
|
+
argument ``coordinates`` in
|
|
2306
|
+
:class:`~sage.manifolds.differentiable.chart.RealDiffChart`; this is
|
|
2307
|
+
used only if the cylindrical chart has not been already defined; if
|
|
2308
|
+
``None`` the symbols are generated as `(\rho,\phi,z)`.
|
|
2309
|
+
- ``names`` -- (default: ``None``) unused argument, except if
|
|
2310
|
+
``symbols`` is not provided; it must be a tuple containing
|
|
2311
|
+
the coordinate symbols (this is guaranteed if the shortcut operator
|
|
2312
|
+
``<,>`` is used)
|
|
2313
|
+
|
|
2314
|
+
OUTPUT:
|
|
2315
|
+
|
|
2316
|
+
- the chart of cylindrical coordinates, as an instance of
|
|
2317
|
+
:class:`~sage.manifolds.differentiable.chart.RealDiffChart`
|
|
2318
|
+
|
|
2319
|
+
EXAMPLES::
|
|
2320
|
+
|
|
2321
|
+
sage: E = EuclideanSpace(3)
|
|
2322
|
+
sage: E.cylindrical_coordinates()
|
|
2323
|
+
Chart (E^3, (rh, ph, z))
|
|
2324
|
+
sage: latex(_)
|
|
2325
|
+
\left(\mathbb{E}^{3},({\rho}, {\phi}, z)\right)
|
|
2326
|
+
sage: E.cylindrical_coordinates().coord_range()
|
|
2327
|
+
rh: (0, +oo); ph: [0, 2*pi] (periodic); z: (-oo, +oo)
|
|
2328
|
+
|
|
2329
|
+
The relation to Cartesian coordinates is::
|
|
2330
|
+
|
|
2331
|
+
sage: E.coord_change(E.cylindrical_coordinates(),
|
|
2332
|
+
....: E.cartesian_coordinates()).display()
|
|
2333
|
+
x = rh*cos(ph)
|
|
2334
|
+
y = rh*sin(ph)
|
|
2335
|
+
z = z
|
|
2336
|
+
sage: E.coord_change(E.cartesian_coordinates(),
|
|
2337
|
+
....: E.cylindrical_coordinates()).display()
|
|
2338
|
+
rh = sqrt(x^2 + y^2)
|
|
2339
|
+
ph = arctan2(y, x)
|
|
2340
|
+
z = z
|
|
2341
|
+
|
|
2342
|
+
The coordinate variables are returned by the square bracket operator::
|
|
2343
|
+
|
|
2344
|
+
sage: E.cylindrical_coordinates()[1]
|
|
2345
|
+
rh
|
|
2346
|
+
sage: E.cylindrical_coordinates()[3]
|
|
2347
|
+
z
|
|
2348
|
+
sage: E.cylindrical_coordinates()[:]
|
|
2349
|
+
(rh, ph, z)
|
|
2350
|
+
|
|
2351
|
+
They can also be obtained via the operator ``<,>``::
|
|
2352
|
+
|
|
2353
|
+
sage: cylindrical.<rh,ph,z> = E.cylindrical_coordinates()
|
|
2354
|
+
sage: cylindrical
|
|
2355
|
+
Chart (E^3, (rh, ph, z))
|
|
2356
|
+
sage: rh, ph, z
|
|
2357
|
+
(rh, ph, z)
|
|
2358
|
+
|
|
2359
|
+
Actually, ``cylindrical.<rh,ph,z> = E.cylindrical_coordinates()`` is a
|
|
2360
|
+
shortcut for::
|
|
2361
|
+
|
|
2362
|
+
sage: cylindrical = E.cylindrical_coordinates()
|
|
2363
|
+
sage: rh, ph, z = cylindrical[:]
|
|
2364
|
+
|
|
2365
|
+
The coordinate symbols can be customized::
|
|
2366
|
+
|
|
2367
|
+
sage: E = EuclideanSpace(3)
|
|
2368
|
+
sage: E.cylindrical_coordinates(symbols=r"R Phi:\Phi Z")
|
|
2369
|
+
Chart (E^3, (R, Phi, Z))
|
|
2370
|
+
sage: latex(E.cylindrical_coordinates())
|
|
2371
|
+
\left(\mathbb{E}^{3},(R, {\Phi}, Z)\right)
|
|
2372
|
+
|
|
2373
|
+
Note that if the cylindrical coordinates have been already initialized,
|
|
2374
|
+
the argument ``symbols`` has no effect::
|
|
2375
|
+
|
|
2376
|
+
sage: E.cylindrical_coordinates(symbols=r"rh:\rho ph:\phi z")
|
|
2377
|
+
Chart (E^3, (R, Phi, Z))
|
|
2378
|
+
"""
|
|
2379
|
+
if self._cylindrical_chart is None:
|
|
2380
|
+
if symbols is None:
|
|
2381
|
+
if names is None:
|
|
2382
|
+
symbols = 'rh:\\rho ph:\\phi z'
|
|
2383
|
+
else:
|
|
2384
|
+
names = list(names)
|
|
2385
|
+
if names[0] in ['rh', 'rho']:
|
|
2386
|
+
names[0] = names[0] + ':\\rho'
|
|
2387
|
+
if names[1] in ['p', 'ph', 'phi']:
|
|
2388
|
+
names[1] = names[1] + ':\\phi'
|
|
2389
|
+
symbols = names[0] + ' ' + names[1] + ' ' + names[2]
|
|
2390
|
+
self._init_cylindrical(symbols)
|
|
2391
|
+
if self._cartesian_chart:
|
|
2392
|
+
self._transition_cylindrical_cartesian()
|
|
2393
|
+
if self._spherical_chart:
|
|
2394
|
+
self._transition_spherical_cylindrical()
|
|
2395
|
+
return self._cylindrical_chart
|
|
2396
|
+
|
|
2397
|
+
def cylindrical_frame(self):
|
|
2398
|
+
r"""
|
|
2399
|
+
Return the orthonormal vector frame associated with cylindrical
|
|
2400
|
+
coordinates.
|
|
2401
|
+
|
|
2402
|
+
OUTPUT: :class:`~sage.manifolds.differentiable.vectorframe.VectorFrame`
|
|
2403
|
+
|
|
2404
|
+
EXAMPLES::
|
|
2405
|
+
|
|
2406
|
+
sage: E = EuclideanSpace(3)
|
|
2407
|
+
sage: E.cylindrical_frame()
|
|
2408
|
+
Vector frame (E^3, (e_rh,e_ph,e_z))
|
|
2409
|
+
sage: E.cylindrical_frame()[1]
|
|
2410
|
+
Vector field e_rh on the Euclidean space E^3
|
|
2411
|
+
sage: E.cylindrical_frame()[:]
|
|
2412
|
+
(Vector field e_rh on the Euclidean space E^3,
|
|
2413
|
+
Vector field e_ph on the Euclidean space E^3,
|
|
2414
|
+
Vector field e_z on the Euclidean space E^3)
|
|
2415
|
+
|
|
2416
|
+
The cylindrical frame expressed in terms of the Cartesian one::
|
|
2417
|
+
|
|
2418
|
+
sage: for e in E.cylindrical_frame():
|
|
2419
|
+
....: e.display(E.cartesian_frame(), E.cylindrical_coordinates())
|
|
2420
|
+
e_rh = cos(ph) e_x + sin(ph) e_y
|
|
2421
|
+
e_ph = -sin(ph) e_x + cos(ph) e_y
|
|
2422
|
+
e_z = e_z
|
|
2423
|
+
|
|
2424
|
+
The orthonormal frame `(e_r, e_\phi, e_z)` expressed in terms of
|
|
2425
|
+
the coordinate frame
|
|
2426
|
+
`\left(\frac{\partial}{\partial r}, \frac{\partial}{\partial\phi},
|
|
2427
|
+
\frac{\partial}{\partial z}\right)`::
|
|
2428
|
+
|
|
2429
|
+
sage: for e in E.cylindrical_frame():
|
|
2430
|
+
....: e.display(E.cylindrical_coordinates())
|
|
2431
|
+
e_rh = ∂/∂rh
|
|
2432
|
+
e_ph = 1/rh ∂/∂ph
|
|
2433
|
+
e_z = ∂/∂z
|
|
2434
|
+
"""
|
|
2435
|
+
if self._cylindrical_frame is None:
|
|
2436
|
+
# create the cylindrical chart and the associated orthonormal frame
|
|
2437
|
+
self.cylindrical_coordinates()
|
|
2438
|
+
return self._cylindrical_frame
|
|
2439
|
+
|
|
2440
|
+
def scalar_triple_product(self, name=None, latex_name=None):
|
|
2441
|
+
r"""
|
|
2442
|
+
Return the scalar triple product operator, as a 3-form.
|
|
2443
|
+
|
|
2444
|
+
The *scalar triple product* (also called *mixed product*) of three
|
|
2445
|
+
vector fields `u`, `v` and `w` defined on a Euclidean space `E`
|
|
2446
|
+
is the scalar field
|
|
2447
|
+
|
|
2448
|
+
.. MATH::
|
|
2449
|
+
|
|
2450
|
+
\epsilon(u,v,w) = u \cdot (v \times w).
|
|
2451
|
+
|
|
2452
|
+
The scalar triple product operator `\epsilon` is a *3-form*, i.e. a
|
|
2453
|
+
field of fully antisymmetric trilinear forms; it is also called the
|
|
2454
|
+
*volume form* of `E` or the *Levi-Civita tensor* of `E`.
|
|
2455
|
+
|
|
2456
|
+
INPUT:
|
|
2457
|
+
|
|
2458
|
+
- ``name`` -- (default: ``None``) string; name given to the scalar
|
|
2459
|
+
triple product operator; if ``None``, ``'epsilon'`` is used
|
|
2460
|
+
- ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote
|
|
2461
|
+
the scalar triple product; if ``None``, it is set to ``r'\epsilon'``
|
|
2462
|
+
if ``name`` is ``None`` and to ``name`` otherwise.
|
|
2463
|
+
|
|
2464
|
+
OUTPUT:
|
|
2465
|
+
|
|
2466
|
+
- the scalar triple product operator `\epsilon`, as an instance of
|
|
2467
|
+
:class:`~sage.manifolds.differentiable.diff_form.DiffFormParal`
|
|
2468
|
+
|
|
2469
|
+
EXAMPLES::
|
|
2470
|
+
|
|
2471
|
+
sage: E.<x,y,z> = EuclideanSpace()
|
|
2472
|
+
sage: triple_product = E.scalar_triple_product()
|
|
2473
|
+
sage: triple_product
|
|
2474
|
+
3-form epsilon on the Euclidean space E^3
|
|
2475
|
+
sage: latex(triple_product)
|
|
2476
|
+
\epsilon
|
|
2477
|
+
sage: u = E.vector_field(x, y, z, name='u')
|
|
2478
|
+
sage: v = E.vector_field(-y, x, 0, name='v')
|
|
2479
|
+
sage: w = E.vector_field(y*z, x*z, x*y, name='w')
|
|
2480
|
+
sage: s = triple_product(u, v, w); s
|
|
2481
|
+
Scalar field epsilon(u,v,w) on the Euclidean space E^3
|
|
2482
|
+
sage: s.display()
|
|
2483
|
+
epsilon(u,v,w): E^3 → ℝ
|
|
2484
|
+
(x, y, z) ↦ x^3*y + x*y^3 - 2*x*y*z^2
|
|
2485
|
+
sage: s.expr()
|
|
2486
|
+
x^3*y + x*y^3 - 2*x*y*z^2
|
|
2487
|
+
sage: latex(s)
|
|
2488
|
+
\epsilon\left(u,v,w\right)
|
|
2489
|
+
sage: s == - triple_product(w, v, u)
|
|
2490
|
+
True
|
|
2491
|
+
|
|
2492
|
+
Check of the identity `\epsilon(u,v,w) = u\cdot(v\times w)`::
|
|
2493
|
+
|
|
2494
|
+
sage: s == u.dot(v.cross(w))
|
|
2495
|
+
True
|
|
2496
|
+
|
|
2497
|
+
Customizing the name::
|
|
2498
|
+
|
|
2499
|
+
sage: E.scalar_triple_product(name='S')
|
|
2500
|
+
3-form S on the Euclidean space E^3
|
|
2501
|
+
sage: latex(_)
|
|
2502
|
+
S
|
|
2503
|
+
sage: E.scalar_triple_product(name='Omega', latex_name=r'\Omega')
|
|
2504
|
+
3-form Omega on the Euclidean space E^3
|
|
2505
|
+
sage: latex(_)
|
|
2506
|
+
\Omega
|
|
2507
|
+
"""
|
|
2508
|
+
eps = self.volume_form()
|
|
2509
|
+
if latex_name is None:
|
|
2510
|
+
if name is None:
|
|
2511
|
+
latex_name = r'\epsilon'
|
|
2512
|
+
else:
|
|
2513
|
+
latex_name = name
|
|
2514
|
+
if name is None:
|
|
2515
|
+
name = 'epsilon'
|
|
2516
|
+
eps.set_name(name=name, latex_name=latex_name)
|
|
2517
|
+
return eps
|