# Pseudo-Riemannian submanifolds¶

An embedded (resp. immersed) submanifold of a pseudo-Riemannian manifold $$(M,g)$$ is an embedded (resp. immersed) submanifold $$N$$ of $$M$$ as a differentiable manifold such that pull back of the metric tensor $$g$$ via the embedding (resp. immersion) endows $$N$$ with the structure of a pseudo-Riemannian manifold.

A limitation of the current implementation is that a foliation is required to perform nearly all the calculations (except the induced metric). This is because the normal vector is easily computed with a foliation, but otherwise requires some operations which are not yet implemented in Sage (contraction over different domains).

To correctly compute the normal vector, the submanifold must be declared either Riemannian or Lorentzian.

The following example explains how to compute the various quantities associated with the hyperbolic slicing of the 3-dimensional Minkowski space.

The manifolds must first be declared:

sage: M = Manifold(3, 'M', structure="Lorentzian")
sage: N = Manifold(2, 'N', ambient=M, structure="Riemannian")


The considered slice being spacelike hypersurfaces, they are Riemannian manifolds.

Let us continue with chart declarations and various free variables:

sage: E.<w,x,y> = M.chart()
sage: C.<rh,th> = N.chart(r'rh:(0,+oo):\rho th:(0,2*pi):\theta')
sage: b = var('b',domain='real')
sage: assume(b>0)
sage: t = var('t',domain='real')


Here $$b$$ is the hyperbola semi major axis, and $$t$$ is the parameter of the foliation.

One must then define the embedding, as well as the inverse embedding and the inverse concerning the foliation parameter:

sage: phi = N.diff_map(M,{(C,E): [b*cosh(rh)+t,
....:                             b*sinh(rh)*cos(th),
....:                             b*sinh(rh)*sin(th)]})
sage: phi_inv = M.diff_map(N,{(E,C):[log(sqrt(x^2+y^2+b^2)/b+
....:                                sqrt((x^2+y^2+b^2)/b^2-1)),
....:                                atan2(y,x)]})
sage: phi_inv_t = M.scalar_field({E:w-sqrt(x^2+y^2+b^2)})


One can check that the inverse is correct with:

sage: (phi*phi_inv).display()
M --> M
(w, x, y) |--> ((b^2 + x^2 + y^2 + sqrt(b^2 + x^2 + y^2)*(t + sqrt(x^2 +
y^2)) + sqrt(x^2 + y^2)*t)/(sqrt(b^2 + x^2 + y^2) + sqrt(x^2 + y^2)), x, y)


The first parameter cannot be evaluated yet, because the inverse for $$t$$ is not taken into account. To prove that it is correct, one can temporarily inject it in the result:

sage: assume(w-t>0)
sage: (phi*phi_inv).expr()[0].subs({b^2: (w-t)^2-x^2-y^2})\
....:           .simplify().expand().simplify_full()
w
sage: forget(w-t>0)


The immersion can then be declared:

sage: N.set_immersion(phi, inverse=phi_inv, var=t,
....:                 t_inverse = {t: phi_inv_t})


This line doesn’t do any calculation yet. It just check the coherence of the arguments, but not the inverse, the user is trusted on this point. The user can also declare that the immersion is in fact an embedding:

sage: N.declare_embedding()


Finally, we initialize the metric of the Minkowski space:

sage: g = M.metric()
sage: g[0,0], g[1,1], g[2,2] = -1, 1, 1


With this, the declaration the ambient manifold and its foliation is finished, and calculations can be performed.

The first step is always to find a chart adapted to the foliation. This is done by the method “adapted_chart”:

sage: T = N.adapted_chart(); T
[Chart (M, (rh_M, th_M, t_M))]


T contains a new chart defined on M. By default, the name of a coordinate will be the name of the coordinate in the submanifold chart indexed by the name of the ambient manifold.

One can check that some coordinates changes have been introduced on $$M$$:

sage: len(M.coord_changes())
2


Let us compute the induced metric (or first fundamental form):

sage: N.induced_metric()[:] # long time
[           b^2              0]
[             0 b^2*sinh(rh)^2]


the normal vector:

sage: N.normal().display()  # long time
n = sqrt(b^2 + x^2 + y^2)/b d/dw + x/b d/dx + y/b d/dy


Check that the hypersurface is indeed spacelike:

sage: N.ambient_metric()(N.normal(), N.normal()).display()  # long time
g(n,n): M --> R
(w, x, y) |--> -1
(rh_M, th_M, t_M) |--> -1


The lapse function is:

sage: N.lapse().display()  # long time
N: M --> R
(w, x, y) |--> sqrt(b^2 + x^2 + y^2)/b
(rh_M, th_M, t_M) |--> cosh(rh_M)


while the shift vector is:

sage: N.shift().display()  # long time
beta = -(x^2 + y^2)/b^2 d/dw - sqrt(b^2 + x^2 + y^2)*x/b^2 d/dx
- sqrt(b^2 + x^2 + y^2)*y/b^2 d/dy


The extrinsic curvature (or second fundamental form) as a tensor of the ambient manifold:

sage: N.ambient_extrinsic_curvature()[:] # long time
[                                 -(x^2 + y^2)/b^3 (b^2*x + x^3 + x*y^2)/(sqrt(b^2 + x^2 + y^2)*b^3) (y^3 + (b^2 + x^2)*y)/(sqrt(b^2 + x^2 + y^2)*b^3)]
[                      sqrt(b^2 + x^2 + y^2)*x/b^3                                  -(b^2 + x^2)/b^3                                          -x*y/b^3]
[                      sqrt(b^2 + x^2 + y^2)*y/b^3                                          -x*y/b^3                                  -(b^2 + y^2)/b^3]


The extrinsic curvature (or second fundamental form) as a tensor of the submanifold:

sage: N.extrinsic_curvature()[:] # long time
[           -b             0]
[            0 -b*sinh(rh)^2]


AUTHORS:

• Florentin Jaffredo (2018): initial version

REFERENCES:

• B. O’Neill : Semi-Riemannian Geometry [ONe1983]
• J. M. Lee : Riemannian Manifolds [Lee1997]
class sage.manifolds.differentiable.pseudo_riemannian_submanifold.PseudoRiemannianSubmanifold(n, name, ambient=None, metric_name='g', signature=None, base_manifold=None, diff_degree=+Infinity, latex_name=None, metric_latex_name=None, start_index=0, category=None, unique_tag=None)

Pseudo-Riemannian submanifold.

An embedded (resp. immersed) submanifold of a pseudo-Riemannian manifold $$(M,g)$$ is an embedded (resp. immersed) submanifold $$N$$ of $$M$$ as a differentiable manifold such that pull back of the metric tensor $$g$$ via the embedding (resp. immersion) endows $$N$$ with the structure of a pseudo-Riemannian manifold.

INPUT:

• n – positive integer; dimension of the manifold

• name – string; name (symbol) given to the manifold

• field – field $$K$$ on which the manifold is defined; allowed values are

• 'real' or an object of type RealField (e.g., RR) for
a manifold over $$\RR$$
• 'complex' or an object of type ComplexField (e.g., CC)
for a manifold over $$\CC$$
• an object in the category of topological fields (see Fields and TopologicalSpaces) for other types of manifolds
• structure – manifold structure (see TopologicalStructure or RealTopologicalStructure)

• ambient – (default: None) manifold of destination of the immersion. If None, set to self

• base_manifold – (default: None) if not None, must be a topological manifold; the created object is then an open subset of base_manifold

• latex_name – (default: None) string; LaTeX symbol to denote the manifold; if none are provided, it is set to name

• start_index – (default: 0) integer; lower value of the range of indices used for “indexed objects” on the manifold, e.g., coordinates in a chart - category – (default: None) to specify the category; if None, Manifolds(field) is assumed (see the category Manifolds)

• unique_tag – (default: None) tag used to force the construction of a new object when all the other arguments have been used previously (without unique_tag, the UniqueRepresentation behavior inherited from ManifoldSubset would return the previously constructed object corresponding to these arguments)

EXAMPLES:

Let $$N$$ be a 2-dimensional submanifold of a 3-dimensional manifold $$M$$:

sage: M = Manifold(3, 'M', structure ="pseudo-Riemannian")
sage: N = Manifold(2, 'N', ambient=M, structure="pseudo-Riemannian")
sage: N
2-dimensional pseudo-Riemannian submanifold N embedded in 3-dimensional
differentiable manifold M
sage: CM.<x,y,z> = M.chart()
sage: CN.<u,v> = N.chart()


Let us define a 1-dimension foliation indexed by $$t$$. The inverse map is needed in order to compute the adapted chart in the ambient manifold:

sage: t = var('t')
sage: phi = N.diff_map(M, {(CN,CM):[u, v, t+u^2+v^2]}); phi
Differentiable map from the 2-dimensional pseudo-Riemannian submanifold
N embedded in 3-dimensional differentiable manifold M to the
3-dimensional Riemannian manifold M
sage: phi_inv = M.diff_map(N,{(CM, CN): [x,y]})
sage: phi_inv_t = M.scalar_field({CM: z-x^2-y^2})


$$\phi$$ can then be declared as an embedding $$N\to M$$:

sage: N.set_embedding(phi, inverse=phi_inv, var=t,
....:                 t_inverse={t: phi_inv_t})


The foliation can also be used to find new charts on the ambient manifold that are adapted to the foliation, ie in which the expression of the immersion is trivial. At the same time, the appropriate coordinate changes are computed:

sage: N.adapted_chart()
[Chart (M, (u_M, v_M, t_M))]
sage: len(M.coord_changes())
2

ambient_extrinsic_curvature()

Return the second fundamental form of the submanifold as a tensor field on the ambient manifold.

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

OUTPUT:

• (0,2) tensor field on the ambient manifold equal to the second fundamental form once orthogonally projected onto the submanifold

EXAMPLES:

A unit circle embedded in the Euclidean plane:

sage: M = Manifold(2, 'M', structure="Riemannian")
sage: N = Manifold(1, 'N', ambient=M, structure="Riemannian")
sage: U = N.open_subset('U')
sage: V = N.open_subset('V')
sage: N.declare_union(U,V)
sage: stereoN.<x> = U.chart()
sage: stereoS.<y> = V.chart()
sage: E.<X,Y> = M.chart()
sage: stereoN_to_S = stereoN.transition_map(stereoS, (4/x),
....:                   intersection_name='W',
....:                   restrictions1=x!=0, restrictions2=y!=0)
sage: stereoS_to_N = stereoN_to_S.inverse()
sage: phi = N.diff_map(M, {(stereoN, E): [1/sqrt(1+x^2/4),x/2/sqrt(1+x^2/4)],
....:         (stereoS, E): [1/sqrt(1+4/y^2),2/y/sqrt(1+4/y^2)]})
sage: N.set_embedding(phi)
sage: g = M.metric()
sage: g[0,0], g[1,1] = 1, 1
sage: N.ambient_second_fundamental_form()  # long time
Field of symmetric bilinear forms K along the 1-dimensional
pseudo-Riemannian submanifold N embedded in 2-dimensional
differentiable manifold M with values on the 2-dimensional
Riemannian manifold M
sage: N.ambient_second_fundamental_form()[:] # long time
[-x^2/(x^2 + 4)  2*x/(x^2 + 4)]
[ 2*x/(x^2 + 4)   -4/(x^2 + 4)]


An alias is ambient_extrinsic_curvature:

sage: N.ambient_extrinsic_curvature()[:]  # long time
[-x^2/(x^2 + 4)  2*x/(x^2 + 4)]
[ 2*x/(x^2 + 4)   -4/(x^2 + 4)]

ambient_first_fundamental_form()

Return the first fundamental form of the submanifold as a tensor of the ambient manifold.

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

OUTPUT:

• (0,2) tensor field on the ambient manifold describing the induced metric before projection on the submanifold

EXAMPLES:

A unit circle embedded in the Euclidean plane:

sage: M = Manifold(2, 'M', structure="Riemannian")
sage: N = Manifold(1, 'N', ambient=M, structure="Riemannian")
sage: U = N.open_subset('U')
sage: V = N.open_subset('V')
sage: N.declare_union(U,V)
sage: stereoN.<x> = U.chart()
sage: stereoS.<y> = V.chart()
sage: E.<X,Y> = M.chart()
sage: stereoN_to_S = stereoN.transition_map(stereoS, (4/x),
....:                   intersection_name='W',
....:                   restrictions1=x!=0, restrictions2=y!=0)
sage: stereoS_to_N = stereoN_to_S.inverse()
sage: phi = N.diff_map(M, {(stereoN, E): [1/sqrt(1+x^2/4),x/2/sqrt(1+x^2/4)],
....:         (stereoS, E): [1/sqrt(1+4/y^2),2/y/sqrt(1+4/y^2)]})
sage: N.set_embedding(phi)
sage: g = M.metric()
sage: g[0,0], g[1,1] = 1, 1
sage: N.ambient_first_fundamental_form()[:]
[ x^2/(x^2 + 4) -2*x/(x^2 + 4)]
[-2*x/(x^2 + 4)    4/(x^2 + 4)]


An alias is ambient_induced_metric:

sage: N.ambient_induced_metric()[:]
[ x^2/(x^2 + 4) -2*x/(x^2 + 4)]
[-2*x/(x^2 + 4)    4/(x^2 + 4)]

ambient_induced_metric()

Return the first fundamental form of the submanifold as a tensor of the ambient manifold.

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

OUTPUT:

• (0,2) tensor field on the ambient manifold describing the induced metric before projection on the submanifold

EXAMPLES:

A unit circle embedded in the Euclidean plane:

sage: M = Manifold(2, 'M', structure="Riemannian")
sage: N = Manifold(1, 'N', ambient=M, structure="Riemannian")
sage: U = N.open_subset('U')
sage: V = N.open_subset('V')
sage: N.declare_union(U,V)
sage: stereoN.<x> = U.chart()
sage: stereoS.<y> = V.chart()
sage: E.<X,Y> = M.chart()
sage: stereoN_to_S = stereoN.transition_map(stereoS, (4/x),
....:                   intersection_name='W',
....:                   restrictions1=x!=0, restrictions2=y!=0)
sage: stereoS_to_N = stereoN_to_S.inverse()
sage: phi = N.diff_map(M, {(stereoN, E): [1/sqrt(1+x^2/4),x/2/sqrt(1+x^2/4)],
....:         (stereoS, E): [1/sqrt(1+4/y^2),2/y/sqrt(1+4/y^2)]})
sage: N.set_embedding(phi)
sage: g = M.metric()
sage: g[0,0], g[1,1] = 1, 1
sage: N.ambient_first_fundamental_form()[:]
[ x^2/(x^2 + 4) -2*x/(x^2 + 4)]
[-2*x/(x^2 + 4)    4/(x^2 + 4)]


An alias is ambient_induced_metric:

sage: N.ambient_induced_metric()[:]
[ x^2/(x^2 + 4) -2*x/(x^2 + 4)]
[-2*x/(x^2 + 4)    4/(x^2 + 4)]

ambient_metric()

Return the metric of the ambient manifold.

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

OUTPUT:

• the metric of the ambient manifold

EXAMPLES:

A sphere embedded in Euclidean space:

sage: M = Manifold(3, 'M', structure="Riemannian")
sage: N = Manifold(2, 'N', ambient=M, structure="Riemannian")
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
sage: r = var('r')
sage: assume(r>0)
sage: E.<x,y,z> = M.chart()
sage: phi = N.diff_map(M,{(C,E): [r*sin(th)*cos(ph),
....:                             r*sin(th)*sin(ph),
....:                             r*cos(th)]})
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
....:                 t_inverse={r: phi_inv_r})
sage: g = M.metric()
sage: g[0,0], g[1,1], g[2,2] = 1, 1, 1
sage: N.ambient_metric()[:]
[1 0 0]
[0 1 0]
[0 0 1]
sage: N.ambient_metric() is g
True

ambient_second_fundamental_form()

Return the second fundamental form of the submanifold as a tensor field on the ambient manifold.

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

OUTPUT:

• (0,2) tensor field on the ambient manifold equal to the second fundamental form once orthogonally projected onto the submanifold

EXAMPLES:

A unit circle embedded in the Euclidean plane:

sage: M = Manifold(2, 'M', structure="Riemannian")
sage: N = Manifold(1, 'N', ambient=M, structure="Riemannian")
sage: U = N.open_subset('U')
sage: V = N.open_subset('V')
sage: N.declare_union(U,V)
sage: stereoN.<x> = U.chart()
sage: stereoS.<y> = V.chart()
sage: E.<X,Y> = M.chart()
sage: stereoN_to_S = stereoN.transition_map(stereoS, (4/x),
....:                   intersection_name='W',
....:                   restrictions1=x!=0, restrictions2=y!=0)
sage: stereoS_to_N = stereoN_to_S.inverse()
sage: phi = N.diff_map(M, {(stereoN, E): [1/sqrt(1+x^2/4),x/2/sqrt(1+x^2/4)],
....:         (stereoS, E): [1/sqrt(1+4/y^2),2/y/sqrt(1+4/y^2)]})
sage: N.set_embedding(phi)
sage: g = M.metric()
sage: g[0,0], g[1,1] = 1, 1
sage: N.ambient_second_fundamental_form()  # long time
Field of symmetric bilinear forms K along the 1-dimensional
pseudo-Riemannian submanifold N embedded in 2-dimensional
differentiable manifold M with values on the 2-dimensional
Riemannian manifold M
sage: N.ambient_second_fundamental_form()[:] # long time
[-x^2/(x^2 + 4)  2*x/(x^2 + 4)]
[ 2*x/(x^2 + 4)   -4/(x^2 + 4)]


An alias is ambient_extrinsic_curvature:

sage: N.ambient_extrinsic_curvature()[:]  # long time
[-x^2/(x^2 + 4)  2*x/(x^2 + 4)]
[ 2*x/(x^2 + 4)   -4/(x^2 + 4)]

clear_cache()

Reset all the cached functions and the derived quantities.

Use this function if you modified the immersion (or embedding) of the submanifold. Note that when calling a calculus function after clearing, new Python objects will be created.

EXAMPLES:

sage: M = Manifold(3, 'M', structure="Riemannian")
sage: N = Manifold(2, 'N', ambient=M, structure="Riemannian")
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
sage: r = var('r')
sage: assume(r>0)
sage: E.<x,y,z> = M.chart()
sage: phi = N.diff_map(M,{(C,E): [r*sin(th)*cos(ph),
....:                             r*sin(th)*sin(ph),
....:                             r*cos(th)]})
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
....:                 t_inverse={r: phi_inv_r})
sage: g = M.metric()
sage: g[0,0], g[1,1], g[2,2] = 1, 1, 1
sage: n = N.normal()
sage: n is N.normal()
True
sage: N.clear_cache()
sage: n is N.normal()
False

difft()

Return the differential of the first scalar field defining the submanifold

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

OUTPUT:

• 1-form field on the ambient manifold.

EXAMPLES:

A sphere embedded in Euclidean space:

sage: M = Manifold(3, 'M', structure="Riemannian")
sage: N = Manifold(2, 'N', ambient=M, structure="Riemannian")
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
sage: r = var('r')
sage: assume(r>0)
sage: E.<x,y,z> = M.chart()
sage: phi = N.diff_map(M,{(C,E): [r*sin(th)*cos(ph),
....:                             r*sin(th)*sin(ph),
....:                             r*cos(th)]})
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
....:                 t_inverse={r: phi_inv_r})
sage: g = M.metric()
sage: g[0,0], g[1,1], g[2,2] = 1, 1, 1
sage: N.difft().display()
dr = x/sqrt(x^2 + y^2 + z^2) dx + y/sqrt(x^2 + y^2 + z^2) dy +
z/sqrt(x^2 + y^2 + z^2) dz

extrinsic_curvature()

Return the second fundamental form of the submanifold.

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

OUTPUT:

• the second fundamental form, as a symmetric tensor field of type (0,2) on the submanifold

EXAMPLES:

A unit circle embedded in the Euclidean plane:

sage: M = Manifold(2, 'M', structure="Riemannian")
sage: N = Manifold(1, 'N', ambient=M, structure="Riemannian")
sage: U = N.open_subset('U')
sage: V = N.open_subset('V')
sage: N.declare_union(U,V)
sage: stereoN.<x> = U.chart()
sage: stereoS.<y> = V.chart()
sage: E.<X,Y> = M.chart()
sage: stereoN_to_S = stereoN.transition_map(stereoS, (4/x),
....:                   intersection_name='W',
....:                   restrictions1=x!=0, restrictions2=y!=0)
sage: stereoS_to_N = stereoN_to_S.inverse()
sage: phi = N.diff_map(M, {(stereoN, E): [1/sqrt(1+x^2/4),x/2/sqrt(1+x^2/4)],
....:         (stereoS, E): [1/sqrt(1+4/y^2),2/y/sqrt(1+4/y^2)]})
sage: N.set_embedding(phi)
sage: g = M.metric()
sage: g[0,0], g[1,1] = 1, 1
sage: N.second_fundamental_form() # long time
Field of symmetric bilinear forms K on the 1-dimensional
pseudo-Riemannian submanifold N embedded in 2-dimensional
differentiable manifold M
sage: N.second_fundamental_form().display() # long time
K = -4/(x^4 + 8*x^2 + 16) dx*dx


An alias is extrinsic_curvature:

sage: N.extrinsic_curvature().display()  # long time
K = -4/(x^4 + 8*x^2 + 16) dx*dx

first_fundamental_form()

Return the first fundamental form of the submanifold.

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

OUTPUT:

EXAMPLES:

A sphere embedded in Euclidean space:

sage: M = Manifold(3, 'M', structure="Riemannian")
sage: N = Manifold(2, 'N', ambient=M, structure="Riemannian")
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
sage: r = var('r')
sage: assume(r>0)
sage: E.<x,y,z> = M.chart()
sage: phi = N.diff_map(M,{(C,E): [r*sin(th)*cos(ph),
....:                             r*sin(th)*sin(ph),
....:                             r*cos(th)]})
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
....:                 t_inverse={r: phi_inv_r})
sage: g = M.metric()
sage: g[0,0], g[1,1], g[2,2] = 1, 1, 1
sage: N.first_fundamental_form()  # long time
Riemannian metric gamma on the 2-dimensional pseudo-Riemannian
submanifold N embedded in 3-dimensional differentiable manifold M
sage: N.first_fundamental_form()[:]  # long time
[          r^2             0]
[            0 r^2*sin(th)^2]


An alias is induced_metric:

sage: N.induced_metric()[:]  # long time
[          r^2             0]
[            0 r^2*sin(th)^2]

gauss_curvature()

Return the Gauss curvature of the submanifold.

The Gauss curvature is the product or the principal curvatures, or equivalently the determinant of the projection operator.

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

OUTPUT:

• the Gauss curvature as a scalar field on the submanifold

EXAMPLES:

A unit circle embedded in the Euclidean plane:

sage: M = Manifold(2, 'M', structure="Riemannian")
sage: N = Manifold(1, 'N', ambient=M, structure="Riemannian")
sage: U = N.open_subset('U')
sage: V = N.open_subset('V')
sage: N.declare_union(U,V)
sage: stereoN.<x> = U.chart()
sage: stereoS.<y> = V.chart()
sage: E.<X,Y> = M.chart()
sage: stereoN_to_S = stereoN.transition_map(stereoS, (4/x),
....:                   intersection_name='W',
....:                   restrictions1=x!=0, restrictions2=y!=0)
sage: stereoS_to_N = stereoN_to_S.inverse()
sage: phi = N.diff_map(M, {(stereoN, E): [1/sqrt(1+x^2/4), x/2/sqrt(1+x^2/4)],
....:         (stereoS, E): [1/sqrt(1+4/y^2), 2/y/sqrt(1+4/y^2)]})
sage: N.set_embedding(phi)
sage: g = M.metric()
sage: g[0,0], g[1,1] = 1, 1
sage: N.gauss_curvature().display()  # long time
N --> R
on U: x |--> -1
on V: y |--> -1

gradt()

Return the gradient of the first scalar field defining the submanifold.

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

OUTPUT:

• vector field on the ambient manifold.

EXAMPLES:

A sphere embedded in Euclidean space:

sage: M = Manifold(3, 'M', structure="Riemannian")
sage: N = Manifold(2, 'N', ambient=M, structure="Riemannian")
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
sage: r = var('r')
sage: assume(r>0)
sage: E.<x,y,z> = M.chart()
sage: phi = N.diff_map(M,{(C,E): [r*sin(th)*cos(ph),
....:                             r*sin(th)*sin(ph),
....:                             r*cos(th)]})
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
....:                 t_inverse={r: phi_inv_r})
sage: g = M.metric()
sage: g[0,0], g[1,1], g[2,2] = 1, 1, 1
grad_r = x/sqrt(x^2 + y^2 + z^2) d/dx + y/sqrt(x^2 + y^2 + z^2) d/dy
+ z/sqrt(x^2 + y^2 + z^2) d/dz

induced_metric()

Return the first fundamental form of the submanifold.

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

OUTPUT:

EXAMPLES:

A sphere embedded in Euclidean space:

sage: M = Manifold(3, 'M', structure="Riemannian")
sage: N = Manifold(2, 'N', ambient=M, structure="Riemannian")
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
sage: r = var('r')
sage: assume(r>0)
sage: E.<x,y,z> = M.chart()
sage: phi = N.diff_map(M,{(C,E): [r*sin(th)*cos(ph),
....:                             r*sin(th)*sin(ph),
....:                             r*cos(th)]})
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
....:                 t_inverse={r: phi_inv_r})
sage: g = M.metric()
sage: g[0,0], g[1,1], g[2,2] = 1, 1, 1
sage: N.first_fundamental_form()  # long time
Riemannian metric gamma on the 2-dimensional pseudo-Riemannian
submanifold N embedded in 3-dimensional differentiable manifold M
sage: N.first_fundamental_form()[:]  # long time
[          r^2             0]
[            0 r^2*sin(th)^2]


An alias is induced_metric:

sage: N.induced_metric()[:]  # long time
[          r^2             0]
[            0 r^2*sin(th)^2]

lapse()

Return the lapse function of the foliation.

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

OUTPUT:

• the lapse function, as a scalar field on the ambient manifold

EXAMPLES:

A sphere embedded in Euclidean space:

sage: M = Manifold(3, 'M', structure="Riemannian")
sage: N = Manifold(2, 'N', ambient=M, structure="Riemannian")
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
sage: r = var('r')
sage: assume(r>0)
sage: E.<x,y,z> = M.chart()
sage: phi = N.diff_map(M,{(C,E): [r*sin(th)*cos(ph),
....:                             r*sin(th)*sin(ph),
....:                             r*cos(th)]})
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
....:                 t_inverse={r: phi_inv_r})
sage: g = M.metric()
sage: g[0,0], g[1,1], g[2,2] = 1, 1, 1
sage: N.lapse().display()
N: M --> R
(x, y, z) |--> 1
(th_M, ph_M, r_M) |--> 1

mean_curvature()

Return the mean curvature of the submanifold.

The mean curvature is the arithmetic mean of the principal curvatures, or equivalently the trace of the projection operator.

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

OUTPUT:

• the mean curvature, as a scalar field on the submanifold

EXAMPLES:

A unit circle embedded in the Euclidean plane:

sage: M = Manifold(2, 'M', structure="Riemannian")
sage: N = Manifold(1, 'N', ambient=M, structure="Riemannian")
sage: U = N.open_subset('U')
sage: V = N.open_subset('V')
sage: N.declare_union(U,V)
sage: stereoN.<x> = U.chart()
sage: stereoS.<y> = V.chart()
sage: E.<X,Y> = M.chart()
sage: stereoN_to_S = stereoN.transition_map(stereoS, (4/x),
....:                   intersection_name='W',
....:                   restrictions1=x!=0, restrictions2=y!=0)
sage: stereoS_to_N = stereoN_to_S.inverse()
sage: phi = N.diff_map(M, {(stereoN, E): [1/sqrt(1+x^2/4),x/2/sqrt(1+x^2/4)],
....:         (stereoS, E): [1/sqrt(1+4/y^2),2/y/sqrt(1+4/y^2)]})
sage: N.set_embedding(phi)
sage: g = M.metric()
sage: g[0,0], g[1,1] = 1, 1
sage: N.mean_curvature().display()  # long time
N --> R
on U: x |--> -1
on V: y |--> -1

mixed_projection(tensor, indices=0)

Return de n+1 decomposition of a tensor on the submanifold and the normal vector.

The n+1 decomposition of a tensor of rank $$k$$ can be obtained by contracting each index either with the normal vector or the projection operator of the submanifold (see projector()).

INPUT:

• tensor – any tensor field, eventually along the submanifold if no foliation is provided.
• indices – (default: 0) list of integers containing the indices on which the projection is made on the normal vector. By default, all projections are made on the submanifold. If an integer $$n$$ is provided, the $$n$$ first contractions are made with the normal vector, all the other ones with the orthogonal projection operator.

OUTPUT:

• tensor field of rank $$k$$-len(indices).

EXAMPLES:

A sphere embedded in Euclidean space:

sage: M = Manifold(3, 'M', structure="Riemannian")
sage: N = Manifold(2, 'N', ambient=M, structure="Riemannian")
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
sage: r = var('r')
sage: assume(r>0)
sage: E.<x,y,z> = M.chart()
sage: phi = N.diff_map(M,{(C,E): [r*sin(th)*cos(ph),
....:                             r*sin(th)*sin(ph),
....:                             r*cos(th)]})
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
....:                 t_inverse={r: phi_inv_r})
sage: g = M.metric()
sage: g[0,0], g[1,1], g[2,2] = 1, 1, 1


If indices is not specified, the mixed projection of the ambient metric coincides with the first fundamental form:

sage: gpp = N.mixed_projection(g); gpp  # long time
Tensor field of type (0,2) on the 3-dimensional Riemannian
manifold M
sage: gpp == N.ambient_first_fundamental_form()  # long time
True


The other non redundant projections are:

sage: gnp =  N.mixed_projection(g, [0]); gnp  # long time
1-form on the 3-dimensional Riemannian manifold M


and:

sage: gnn = N.mixed_projection(g, [0,1]); gnn
Scalar field on the 3-dimensional Riemannian manifold M


which is constant and equal to 1 (the norm of the unit normal vector):

sage: gnn.display()
M --> R
(x, y, z) |--> 1
(th_M, ph_M, r_M) |--> 1

normal()

Return a normal unit vector to the submanifold.

If a foliation is defined, it is used to compute the gradient of the foliation parameter and then the normal vector. If not, the normal vector is computed using the following formula:

$n = \vec{*}(\mathrm{d}x_0\wedge\mathrm{d}x_1\wedge... \wedge\mathrm{d}x_{n-1})$

where the star stands for the Hodge dual operator and the wedge for the exterior product.

This formula does not always define a proper vector field when multiple charts overlap, because of the arbitrariness of the direction of the normal vector. To avoid this problem, this function considers the graph defined by the atlas of the submanifold and the changes of coordinates, and only calculate the normal vector once by connected component. The expression is then propagate by restriction, continuation, or change of coordinates using a breadth-first exploration of the graph.

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

OUTPUT:

• vector field on the ambient manifold.

EXAMPLES:

A sphere embedded in Euclidean space foliated on the radius:

sage: M = Manifold(3, 'M', structure="Riemannian")
sage: N = Manifold(2, 'N', ambient=M, structure="Riemannian")
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
sage: r = var('r')
sage: assume(r>0)
sage: E.<x,y,z> = M.chart()
sage: phi = N.diff_map(M,{(C,E): [r*sin(th)*cos(ph),
....:                             r*sin(th)*sin(ph),
....:                             r*cos(th)]})
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
....:                 t_inverse={r: phi_inv_r})
sage: g = M.metric()
sage: g[0,0], g[1,1], g[2,2] = 1, 1, 1
sage: N.normal().display()  # long time
n = x/sqrt(x^2 + y^2 + z^2) d/dx + y/sqrt(x^2 + y^2 + z^2) d/dy
+ z/sqrt(x^2 + y^2 + z^2) d/dz


Or in spherical coordinates:

sage: N.normal().display(T[0].frame(),T[0])  # long time
n = d/dr_M


The same sphere of constant radius, i.e. not assumed to be part of a foliation, in stereographic coordinates:

sage: M = Manifold(3, 'M', structure="Riemannian", start_index=1)
sage: N = Manifold(2, 'N', ambient=M, structure="Riemannian")
sage: U = N.open_subset('U')
sage: V = N.open_subset('V')
sage: N.declare_union(U, V)
sage: stereoN.<x,y> = U.chart()
sage: stereoS.<xp,yp> = V.chart("xp:x' yp:y'")
sage: stereoN_to_S = stereoN.transition_map(stereoS,
....:                                 (x/(x^2+y^2), y/(x^2+y^2)),
....:                                 intersection_name='W',
....:                                 restrictions1= x^2+y^2!=0,
....:                                 restrictions2= xp^2+yp^2!=0)
sage: stereoS_to_N = stereoN_to_S.inverse()
sage: W = U.intersection(V)
sage: stereoN_W = stereoN.restrict(W)
sage: stereoS_W = stereoS.restrict(W)
sage: A = W.open_subset('A', coord_def={stereoN_W: (y!=0, x<0),
....:                                  stereoS_W: (yp!=0, xp<0)})
sage: spher.<the,phi> = A.chart(r'the:(0,pi):\theta phi:(0,2*pi):\phi')
sage: stereoN_A = stereoN_W.restrict(A)
sage: spher_to_stereoN = spher.transition_map(stereoN_A,
....:                              (sin(the)*cos(phi)/(1-cos(the)),
....:                               sin(the)*sin(phi)/(1-cos(the))))
sage: spher_to_stereoN.set_inverse(2*atan(1/sqrt(x^2+y^2)),
....:                                    atan2(-y,-x)+pi)
sage: stereoN_to_S_A = stereoN_to_S.restrict(A)
sage: spher_to_stereoS = stereoN_to_S_A * spher_to_stereoN
sage: stereoS_to_N_A = stereoN_to_S.inverse().restrict(A)
sage: stereoS_to_spher = spher_to_stereoN.inverse() * stereoS_to_N_A
sage: E.<X,Y,Z> = M.chart()
sage: phi = N.diff_map(M, {(stereoN, E): [2*x/(1+x^2+y^2),
....:                                    2*y/(1+x^2+y^2),
....:                                    (x^2+y^2-1)/(1+x^2+y^2)],
....:                   (stereoS, E): [2*xp/(1+xp^2+yp^2),
....:                                  2*yp/(1+xp^2+yp^2),
....:                                 (1-xp^2-yp^2)/(1+xp^2+yp^2)]},
....:                  name='Phi', latex_name=r'\Phi')
sage: N.set_embedding(phi)
sage: g = M.metric()
sage: g[3,3],g[1,1],g[2,2]=1,1,1


The normal vector is computed the same way, but now returns a tensor field along N:

sage: n = N.normal()  # long time
sage: n  # long time
Vector field n along the 2-dimensional pseudo-Riemannian submanifold
N embedded in 3-dimensional differentiable manifold M with values
on the 3-dimensional Riemannian manifold M


Let us check that the choice of orientation is coherent on the two top frames:

sage: n.restrict(V).display(format_spec=spher)  # long time
n = -cos(phi)*sin(the) d/dX - sin(phi)*sin(the) d/dY - cos(the) d/dZ
sage: n.restrict(U).display(format_spec=spher)  # long time
n = -cos(phi)*sin(the) d/dX - sin(phi)*sin(the) d/dY - cos(the) d/dZ

principal_curvatures(chart)

Return the principal curvatures of the submanifold.

The principal curvatures are the eigenvalues of the projection operator. The resulting scalar fields are named k_i with the index i ranging from 0 to the submanifold dimension minus one.

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

INPUT:

• chart – chart in which the principal curvatures are to be computed

OUTPUT:

• the principal curvatures, as a list of scalar fields on the submanifold

EXAMPLES:

A unit circle embedded in the Euclidean plane:

sage: M = Manifold(2, 'M', structure="Riemannian")
sage: N = Manifold(1, 'N', ambient=M, structure="Riemannian")
sage: U = N.open_subset('U')
sage: V = N.open_subset('V')
sage: N.declare_union(U,V)
sage: stereoN.<x> = U.chart()
sage: stereoS.<y> = V.chart()
sage: E.<X,Y> = M.chart()
sage: stereoN_to_S = stereoN.transition_map(stereoS, (4/x),
....:                   intersection_name='W',
....:                   restrictions1=x!=0, restrictions2=y!=0)
sage: stereoS_to_N = stereoN_to_S.inverse()
sage: phi = N.diff_map(M, {(stereoN, E): [1/sqrt(1+x^2/4),x/2/sqrt(1+x^2/4)],
....:         (stereoS, E): [1/sqrt(1+4/y^2),2/y/sqrt(1+4/y^2)]})
sage: N.set_embedding(phi)
sage: g = M.metric()
sage: g[0,0], g[1,1] = 1, 1
sage: N.principal_curvatures(stereoN)[0].display()  # long time
k_0: N --> R
on U: x |--> -1

principal_directions(chart)

Return the principal directions of the submanifold.

The principal directions are the eigenvectors of the projection operator. The result is formatted as a list of couples (eigenvector, eigenvalue).

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

INPUT:

• chart – chart in which the principal directions are to be computed

OUTPUT:

• list of couples (vector field, scalar field) representing the principal directions and the associated principal curvatures

EXAMPLES:

A unit circle embedded in the Euclidean plane:

sage: M = Manifold(2, 'M', structure="Riemannian")
sage: N = Manifold(1, 'N', ambient=M, structure="Riemannian")
sage: U = N.open_subset('U')
sage: V = N.open_subset('V')
sage: N.declare_union(U,V)
sage: stereoN.<x> = U.chart()
sage: stereoS.<y> = V.chart()
sage: E.<X,Y> = M.chart()
sage: stereoN_to_S = stereoN.transition_map(stereoS, (4/x),
....:                   intersection_name='W',
....:                   restrictions1=x!=0, restrictions2=y!=0)
sage: stereoS_to_N = stereoN_to_S.inverse()
sage: phi = N.diff_map(M, {(stereoN, E): [1/sqrt(1+x^2/4),x/2/sqrt(1+x^2/4)],
....:         (stereoS, E): [1/sqrt(1+4/y^2),2/y/sqrt(1+4/y^2)]})
sage: N.set_embedding(phi)
sage: g = M.metric()
sage: g[0,0], g[1,1] = 1, 1
sage: N.principal_directions(stereoN)[0][0].display()  # long time
e_0 = d/dx

project(tensor)

Return the orthogonal projection of a tensor field onto the submanifold.

INPUT:

• tensor – any tensor field to be projected onto the submanifold. If no foliation is provided, must be a tensor field along the submanifold.

OUTPUT:

• orthogonal projection of tensor onto the submanifold, as a tensor field of the ambient manifold

EXAMPLES:

A sphere embedded in Euclidean space:

sage: M = Manifold(3, 'M', structure="Riemannian")
sage: N = Manifold(2, 'N', ambient=M, structure="Riemannian")
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
sage: r = var('r')
sage: assume(r>0)
sage: E.<x,y,z> = M.chart()
sage: phi = N.diff_map(M,{(C,E): [r*sin(th)*cos(ph),
....:                             r*sin(th)*sin(ph),
....:                             r*cos(th)]})
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
....:                 t_inverse={r: phi_inv_r})
sage: g = M.metric()
sage: g[0,0], g[1,1], g[2,2] = 1, 1, 1


Let us perform the projection of the ambient metric and check that it is equal to the first fundamental form:

sage: pg = N.project(g); pg  # long time
Tensor field of type (0,2) on the 3-dimensional Riemannian manifold M
sage: pg == N.ambient_first_fundamental_form()  # long time
True


Note that the result of project is not cached.

projector()

Return the orthogonal projector onto the submanifold.

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

OUTPUT:

• the orthogonal projector onto the submanifold, as tensor field of type (1,1) on the ambient manifold

EXAMPLES:

A sphere embedded in Euclidean space:

sage: M = Manifold(3, 'M', structure="Riemannian")
sage: N = Manifold(2, 'N', ambient=M, structure="Riemannian")
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
sage: r = var('r')
sage: assume(r>0)
sage: E.<x,y,z> = M.chart()
sage: phi = N.diff_map(M,{(C,E): [r*sin(th)*cos(ph),
....:                             r*sin(th)*sin(ph),
....:                             r*cos(th)]})
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
....:                 t_inverse={r: phi_inv_r})
sage: g = M.metric()
sage: g[0,0], g[1,1], g[2,2] = 1, 1, 1


The orthogonal projector onto N as a type-(1,1) tensor field on M:

sage: N.projector()  # long time
Tensor field gamma of type (1,1) on the 3-dimensional Riemannian
manifold M


Check that the orthogonal projector applied to the normal vector is zero:

sage: N.projector().contract(N.normal()).display()  # long time
0

second_fundamental_form()

Return the second fundamental form of the submanifold.

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

OUTPUT:

• the second fundamental form, as a symmetric tensor field of type (0,2) on the submanifold

EXAMPLES:

A unit circle embedded in the Euclidean plane:

sage: M = Manifold(2, 'M', structure="Riemannian")
sage: N = Manifold(1, 'N', ambient=M, structure="Riemannian")
sage: U = N.open_subset('U')
sage: V = N.open_subset('V')
sage: N.declare_union(U,V)
sage: stereoN.<x> = U.chart()
sage: stereoS.<y> = V.chart()
sage: E.<X,Y> = M.chart()
sage: stereoN_to_S = stereoN.transition_map(stereoS, (4/x),
....:                   intersection_name='W',
....:                   restrictions1=x!=0, restrictions2=y!=0)
sage: stereoS_to_N = stereoN_to_S.inverse()
sage: phi = N.diff_map(M, {(stereoN, E): [1/sqrt(1+x^2/4),x/2/sqrt(1+x^2/4)],
....:         (stereoS, E): [1/sqrt(1+4/y^2),2/y/sqrt(1+4/y^2)]})
sage: N.set_embedding(phi)
sage: g = M.metric()
sage: g[0,0], g[1,1] = 1, 1
sage: N.second_fundamental_form() # long time
Field of symmetric bilinear forms K on the 1-dimensional
pseudo-Riemannian submanifold N embedded in 2-dimensional
differentiable manifold M
sage: N.second_fundamental_form().display() # long time
K = -4/(x^4 + 8*x^2 + 16) dx*dx


An alias is extrinsic_curvature:

sage: N.extrinsic_curvature().display()  # long time
K = -4/(x^4 + 8*x^2 + 16) dx*dx

shape_operator()

Return the shape operator of the submanifold.

The shape operator is equal to the second fundamental form with one of the indices upped.

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

OUTPUT:

• the shape operator, as a tensor field of type (1,1) on the submanifold

EXAMPLES:

A unit circle embedded in the Euclidean plane:

sage: M = Manifold(2, 'M', structure="Riemannian")
sage: N = Manifold(1, 'N', ambient=M, structure="Riemannian")
sage: U = N.open_subset('U')
sage: V = N.open_subset('V')
sage: N.declare_union(U,V)
sage: stereoN.<x> = U.chart()
sage: stereoS.<y> = V.chart()
sage: E.<X,Y> = M.chart()
sage: stereoN_to_S = stereoN.transition_map(stereoS, (4/x),
....:                   intersection_name='W',
....:                   restrictions1=x!=0, restrictions2=y!=0)
sage: stereoS_to_N = stereoN_to_S.inverse()
sage: phi = N.diff_map(M, {(stereoN, E): [1/sqrt(1+x^2/4),x/2/sqrt(1+x^2/4)],
....:         (stereoS, E): [1/sqrt(1+4/y^2),2/y/sqrt(1+4/y^2)]})
sage: N.set_embedding(phi)
sage: g = M.metric()
sage: g[0,0], g[1,1] = 1, 1
sage: N.shape_operator()  # long time
Tensor field of type (1,1) on the 1-dimensional pseudo-Riemannian
submanifold N embedded in 2-dimensional differentiable manifold M
sage: N.shape_operator()[:]  # long time
[-1]

shift()

Return the shift function of the foliation

The result is cached, so calling this method multiple times always returns the same result at no additional cost.

OUTPUT:

• shift vector field on the ambient manifold.

EXAMPLES:

A sphere embedded in Euclidean space:

sage: M = Manifold(3, 'M', structure="Riemannian")
sage: N = Manifold(2, 'N', ambient=M, structure="Riemannian")
sage: C.<th,ph> = N.chart(r'th:(0,pi):\theta ph:(-pi,pi):\phi')
sage: r = var('r')
sage: assume(r>0)
sage: E.<x,y,z> = M.chart()
sage: phi = N.diff_map(M,{(C,E): [r*sin(th)*cos(ph),
....:                             r*sin(th)*sin(ph),
....:                             r*cos(th)]})
sage: phi_inv = M.diff_map(N, {(E,C): [arccos(z/r), atan2(y,x)]})
sage: phi_inv_r = M.scalar_field({E: sqrt(x^2+y^2+z^2)})
sage: N.set_embedding(phi, inverse=phi_inv, var=r,
....:                 t_inverse={r: phi_inv_r})