Opened 4 years ago

Closed 4 years ago

# Pseudo-Riemannian manifods

Reported by: Owned by: egourgoulhon major sage-8.2 geometry pseudo-Riemannian, Riemannian, manifold, gradient, divergence, Laplacian tscrim Eric Gourgoulhon Travis Scrimshaw, John Palmieri N/A 185e438 185e438b808c204dbf7b1f7b838fb43e40c100d2

This ticket implements pseudo-Riemannian manifolds, i.e. real differentiable manifolds equipped with a metric tensor. Important subcases are of course Riemannian manifolds and Lorentzian manifolds. Taking into account that pseudo-Riemannian metric tensors are already implemented in Sage (see here), this ticket introduces

• the parent class PseudoRiemannianManifold, as a subclass of the existing class DifferentiableManifold, with the specific methods metric and volume_form
• new methods gradient, laplacian and dalembertian for scalar fields
• new methods divergence, laplacian and dalembertian for tensor fields
• new methods curl, dot_product, cross_product and norm for vector fields

For a greater generality, all these methods have an optional argument metric; if it is omitted, the metric of the underlying pseudo-Riemannian manifold is assumed.

To match with the standard functional notation, functions grad, div, curl, laplacian and dalembertian have been implemented in src/sage/manifolds/differentiable/operators.py. Their role is simply to call the corresponding methods on their arguments. In order not to clutter the global namespace in a standard Sage session, these functions are imported only if some pseudo-Riemannian manifold is constructed, via the call to sage.repl.user_globals.set_global in PseudoRiemannianManifold.__init__.

Some vector calculus functionalities introduced by this ticket are demonstrated in this Jupyter worksheet.

The follow-up ticket #24623 implements Euclidean spaces.

This work is part of the SageManifolds project, see #18528 for an overview.

### comment:1 Changed 4 years ago by egourgoulhon

• Branch set to public/manifolds/pseudoRiemannian
• Commit set to 06f8fd34981fb8b201134439a55ecf79f962a5c9

This is work in progress...

New commits:

 ​8e1148c First version of pseudo-Riemannian manifold class ​8e56cf3 Pseudo-Riemannian manifolds constructed by the generic function Manifold ​ce3a617 Divergence of a tensor field + new section on pseudo-Riemannian manifolds in the reference manual ​06f8fd3 Add doctests for pseudo-Riemannian manifolds

### comment:2 Changed 4 years ago by egourgoulhon

• Description modified (diff)

### comment:3 Changed 4 years ago by egourgoulhon

• Description modified (diff)

### comment:4 Changed 4 years ago by git

• Commit changed from 06f8fd34981fb8b201134439a55ecf79f962a5c9 to 55f356c2ee79026349a821dccd409d0d5a76718c

Branch pushed to git repo; I updated commit sha1. New commits:

 ​55f356c Improve documentation of pseudo-Riemannian manifolds

### comment:5 Changed 4 years ago by git

• Commit changed from 55f356c2ee79026349a821dccd409d0d5a76718c to 0fc661a5beaf076fdf67e0d4f45b546ed8e23e8e

Branch pushed to git repo; I updated commit sha1. New commits:

 ​0fc661a Remove method set_metric and improve doc of pseudo-Riemannian manifolds

### comment:6 Changed 4 years ago by git

• Commit changed from 0fc661a5beaf076fdf67e0d4f45b546ed8e23e8e to b4dddf74279a21aa9cc645f959c8cd6b513a8d48

Branch pushed to git repo; I updated commit sha1. New commits:

 ​b4dddf7 Add operators Laplacian, d'Alembertian and curl on pseudo-Riemannian manifolds

### comment:7 Changed 4 years ago by git

• Commit changed from b4dddf74279a21aa9cc645f959c8cd6b513a8d48 to 040b01c35f3082b4788bdeefea9d28aa1f96d3bc

Branch pushed to git repo; I updated commit sha1. New commits:

 ​040b01c Add dot product and cross product of vector fields

### comment:8 Changed 4 years ago by git

• Commit changed from 040b01c35f3082b4788bdeefea9d28aa1f96d3bc to 46b8f66385cd1c34e5310d627a0e44983f87cc4a

Branch pushed to git repo; I updated commit sha1. New commits:

 ​46b8f66 Add norm of vector fields.

### comment:9 Changed 4 years ago by egourgoulhon

• Description modified (diff)

### comment:10 Changed 4 years ago by git

• Commit changed from 46b8f66385cd1c34e5310d627a0e44983f87cc4a to 135af976131baf0d1551806a7be1be25ef0e06c0

Branch pushed to git repo; I updated commit sha1. New commits:

 ​135af97 Add method volume_form() to class PseudoRiemannianManifold

### comment:11 Changed 4 years ago by git

• Commit changed from 135af976131baf0d1551806a7be1be25ef0e06c0 to 38e8fd3d9ab08783ec58dc973b3fb5575a3b79a2

Branch pushed to git repo; I updated commit sha1. New commits:

 ​38e8fd3 Add global functions grad, div, curl, etc. for vector/tensor operators on pseudo-Riemannian manifolds

### comment:12 Changed 4 years ago by git

• Commit changed from 38e8fd3d9ab08783ec58dc973b3fb5575a3b79a2 to 8309fdd68066fd62b180f95be415f02ff2f7895e

Branch pushed to git repo; I updated commit sha1. New commits:

 ​8309fdd Improve documentation for operators on pseudo-Riemannian manifolds

### comment:13 Changed 4 years ago by egourgoulhon

• Description modified (diff)

### comment:14 Changed 4 years ago by egourgoulhon

• Status changed from new to needs_review

### comment:15 follow-up: ↓ 16 Changed 4 years ago by tscrim

The biggest issue I have with this ticket is the addition of functions to the global namespace. curl, laplacian, and dalembertian I think are okay. grad over gradient I am not sure about. div looks too much like it is coming from "divide" or "division". I think you should ask on sage-devel to see if anyone has any objections with adding these to the global namespace and about them being a simple re-direct. (Ralf may want to have them interact with the symbolics in some way.)

In the same vein, this is bad to me:

# Import differential operators in the user global namespace:
curl, laplacian, dalembertian)
set_global('div', div)
set_global('curl', curl)
set_global('rot', curl)
set_global('laplacian', laplacian)
set_global('dalembertian', dalembertian)

I think a much better way is just to either have them all in the global namespace at start or having some function inject_functions(), but with some better name than I can come up with in 5 seconds.

This is under-indetented:

• ## src/sage/manifolds/differentiable/tensorfield.py

diff --git a/src/sage/manifolds/differentiable/tensorfield.py b/src/sage/manifolds/differentiable/tensorfield.py
index 63ace1d..d8d173c 100644
 a class TensorField(ModuleElement): .. MATH:: (T^\sharp)^{a_1\ldots a_{k+1}}_{\qquad\ \ b_1 \ldots b_{l-1}} = g^{a_{k+1} i} \, T^{a_1\ldots a_k}_{\qquad\  b_1 \ldots b_{p-k} \, i \, b_{p-k+1}\ldots b_{l-1}}, (T^\sharp)^{a_1\ldots a_{k+1}}_{\phantom{a_1\ldots a_{k+1}}\, b_1 \ldots b_{l-1}} = g^{a_{k+1} i} \, T^{a_1\ldots a_k}_{\phantom{a_1\ldots a_k}\, b_1 \ldots b_{p-k} \, i \, b_{p-k+1}\ldots b_{l-1}}, g^{ab} being the components of the inverse metric. class TensorField(ModuleElement): .. MATH:: (T^\flat)^{a_1\ldots a_{k-1}}_{\qquad\ \ b_1 \ldots b_{l+1}} = g_{b_1 i} \, T^{a_1\ldots a_{p} \, i \, a_{p+1}\ldots a_{k-1}}_{\qquad\qquad\quad\; b_2 \ldots b_{l+1}}, (T^\flat)^{a_1\ldots a_{k-1}}_{\phantom{a_1\ldots a_{k-1}}\, b_1 \ldots b_{l+1}} = g_{b_1 i} \, T^{a_1\ldots a_{p} \, i \, a_{p+1}\ldots a_{k-1}}_{\phantom{a_1\ldots a_{p} \, i \, a_{p+1}\ldots a_{k-1}}\, b_2 \ldots b_{l+1}}, g_{ab} being the components of the metric tensor.

(It's okay that not everything in a .. MATH:: block, but I do prefer the >= 4 spaces indentation visually.)

Everything else LGTM.

### comment:16 in reply to: ↑ 15 ; follow-up: ↓ 17 Changed 4 years ago by egourgoulhon

The biggest issue I have with this ticket is the addition of functions to the global namespace. curl, laplacian, and dalembertian I think are okay. grad over gradient I am not sure about. div looks too much like it is coming from "divide" or "division".

I agree that div may evoke "division", however grad and div are pretty much standard notations in both elementary vector calculus and differential geometry, see e.g.

As a side note, neither grad nor div is already used as a global function in Sage, so the slot is free.

I think you should ask on sage-devel to see if anyone has any objections with adding these to the global namespace and about them being a simple re-direct.

OK I will.

In the same vein, this is bad to me:

# Import differential operators in the user global namespace:
curl, laplacian, dalembertian)
set_global('div', div)
set_global('curl', curl)
set_global('rot', curl)
set_global('laplacian', laplacian)
set_global('dalembertian', dalembertian)

I think a much better way is just to either have them all in the global namespace at start or having some function inject_functions(), but with some better name than I can come up with in 5 seconds.

Why is it bad? Is it because it prevents the user from discovering the grad function with the TAB key and/or grad? before having set up any pseudo-Riemannian manifold? This would indeed be a good reason to have the operators in the global namespace at start.

This is under-indetented: (It's okay that not everything in a .. MATH:: block, but I do prefer the >= 4 spaces indentation visually.)

OK, I will correct this.

Last edited 4 years ago by egourgoulhon (previous) (diff)

### comment:17 in reply to: ↑ 16 ; follow-up: ↓ 18 Changed 4 years ago by tscrim

The biggest issue I have with this ticket is the addition of functions to the global namespace. curl, laplacian, and dalembertian I think are okay. grad over gradient I am not sure about. div looks too much like it is coming from "divide" or "division".

I agree that div may evoke "division", however grad and div are pretty much standard notations in both elementary vector calculus and differential geometry, see e.g.

As a side note, neither grad nor div is already used as a global function in Sage, so the slot is free.

The difference is that in those links, you know you are doing vector calculus, whereas in Python you have operator.div.

In the same vein, this is bad to me:

# Import differential operators in the user global namespace:
curl, laplacian, dalembertian)
set_global('div', div)
set_global('curl', curl)
set_global('rot', curl)
set_global('laplacian', laplacian)
set_global('dalembertian', dalembertian)

I think a much better way is just to either have them all in the global namespace at start or having some function inject_functions(), but with some better name than I can come up with in 5 seconds.

Why is it bad? Is it because it prevents the user from discovering the grad function with the TAB key and/or grad? before having set up any pseudo-Riemannian manifold? This would indeed be a good reason to have the operators in the global namespace at start.

You should not inject them without the user knowing. In particular, what if you have rot = some expensive computation, then you create your manifold (with not having created a grad) and all of a sudden, your rot computation is gone. On the other side, what if we add a different grad to the global namespace, something I think could happen, then you will not get these injections.

I agree that they should be in the global namespace from the start and would making this issue moot. Some other thoughts that come to my mind is a function like setup_manifolds_environment and/or getting people who use SageManifolds to have a specific section to their .sage/init.sage file.

### comment:18 in reply to: ↑ 17 Changed 4 years ago by egourgoulhon

The difference is that in those links, you know you are doing vector calculus, whereas in Python you have operator.div.

Yes I agree, this depends on the context.

You should not inject them without the user knowing. In particular, what if you have rot = some expensive computation, then you create your manifold (with not having created a grad) and all of a sudden, your rot computation is gone. On the other side, what if we add a different grad to the global namespace, something I think could happen, then you will not get these injections.

Thanks for these explanations. I totally overlooked this point... I am now 100% convinced that injecting silently names in the global namespace is a very bad thing.

I agree that they should be in the global namespace from the start and would making this issue moot. Some other thoughts that come to my mind is a function like setup_manifolds_environment and/or getting people who use SageManifolds to have a specific section to their .sage/init.sage file.

### comment:19 Changed 4 years ago by git

• Commit changed from 8309fdd68066fd62b180f95be415f02ff2f7895e to 18b63a6de6dcceed8b29edc339d8e301785b5a03

Branch pushed to git repo; I updated commit sha1. New commits:

 ​18b63a6 Differential operators are no longer imported in the global namespace by PseudoRiemannianManifold.__init__

### comment:20 Changed 4 years ago by egourgoulhon

Following the conclusions of the sage-devel thread, the above commit allows only explicit imports of the type:

sage: from sage.manifolds.operators import *

to inject the differential operators in the global namespace (the demo worksheet has been updated accordingly). Besides, this commit corrects the indentation of .. MATH blocks mentioned in comment:15.

Last edited 4 years ago by egourgoulhon (previous) (diff)

### comment:21 follow-up: ↓ 24 Changed 4 years ago by tscrim

One little trivial thing: the functions are no longer global (at least, I am interpreting that as being in the global namespace):

-        The function :func:~sage.manifolds.operators.laplacian can be
+        The global function :func:~sage.manifolds.operators.laplacian can be
+        used instead of the method laplacian()::

and similar for div and curl, etc. Also, do you want to link laplacition() to a (the?) corresponding method via :meth:?

### comment:22 follow-up: ↓ 25 Changed 4 years ago by jhpalmieri

A few typos with proposed corrections:

• ## src/sage/manifolds/differentiable/pseudo_riemannian.py

diff --git a/src/sage/manifolds/differentiable/pseudo_riemannian.py b/src/sage/manifolds/differentiable/pseudo_riemannian.py
index fcfbe500e1..d68d797096 100644
 a Pseudo-Riemannian Manifolds A *pseudo-Riemannian manifold* is a pair (M,g) where M is a real differentiable manifold M (see :class:~sage.manifolds.differentiable.manifold.DifferentiableManifold) and g is a field non-degenerate symmetric bilinear forms on M, which is and g is a field of non-degenerate symmetric bilinear forms on M, which is called the *metric tensor*, or simply the *metric* (see :class:~sage.manifolds.differentiable.metric.PseudoRiemannianMetric). We get the metric defining the Riemannian structure by:: sage: g Riemannian metric g on the 2-dimensional Riemannian manifold S^2 At this stage, the metric g is defined a Python object but there remains to At this stage, the metric g is defined as a Python object but there remains to initialize it by setting its components with respect to the vector frames associated with the stereographic coordinates. Let us begin with the frame of chart stereoN:: manifold, we can get the metric on it via the method metric():: sage: gU.display() g = 4/(x^2 + y^2 + 1)^2 dx*dx + 4/(x^2 + y^2 + 1)^2 dy*dy On course, gU is nothing but the restriction of g to U:: Of course, gU is nothing but the restriction of g to U:: sage: gU is g.restrict(U) True On course, gU is nothing but the restriction of g to U:: .. RUBRIC:: Example 2: Minkowski spacetime as a Lorentzian manifold of dimension 4 We start by declaring 4-dimensional Lorentzian manifold:: We start by declaring a 4-dimensional Lorentzian manifold:: sage: M = Manifold(4, 'M', structure='Lorentzian') sage: M class PseudoRiemannianManifold(DifferentiableManifold): A *pseudo-Riemannian manifold* is a pair (M,g) where M is a real differentiable manifold M (see :class:~sage.manifolds.differentiable.manifold.DifferentiableManifold) and g is a field non-degenerate symmetric bilinear forms on M, which is and g is a field of non-degenerate symmetric bilinear forms on M, which is called the *metric tensor*, or simply the *metric* (see :class:~sage.manifolds.differentiable.metric.PseudoRiemannianMetric). class PseudoRiemannianManifold(DifferentiableManifold): dest_map=None): r""" Return the metric giving the pseudo-Riemannian structure to the manifold, or defines a new metric tensor on the manifold. manifold, or define a new metric tensor on the manifold. INPUT:

### comment:23 Changed 4 years ago by git

• Commit changed from 18b63a6de6dcceed8b29edc339d8e301785b5a03 to 185e438b808c204dbf7b1f7b838fb43e40c100d2

Branch pushed to git repo; I updated commit sha1. New commits:

 ​185e438 Improve documentation of pseudo-Riemannian manifolds

### comment:24 in reply to: ↑ 21 Changed 4 years ago by egourgoulhon

One little trivial thing: the functions are no longer global (at least, I am interpreting that as being in the global namespace):

and similar for div and curl, etc. Also, do you want to link laplacition() to a (the?) corresponding method via :meth:?

Thanks for pointing this. This is corrected in the above commit. I have also added some simple vector fields in the Minkowski spacetime example (example 2 at the top of pseudo_riemannian.py).

### comment:25 in reply to: ↑ 22 Changed 4 years ago by egourgoulhon

A few typos with proposed corrections:

Thank you very much for these corrections. They are effective in the above commit.

### comment:26 Changed 4 years ago by tscrim

• Reviewers set to Travis Scrimshaw, John Palmieri
• Status changed from needs_review to positive_review

LGTM. Thank you.

### comment:27 Changed 4 years ago by egourgoulhon

Thank you very much for the review!

### comment:28 Changed 4 years ago by vbraun

• Branch changed from public/manifolds/pseudoRiemannian to 185e438b808c204dbf7b1f7b838fb43e40c100d2
• Resolution set to fixed
• Status changed from positive_review to closed
Note: See TracTickets for help on using tickets.