Opened 22 months ago
Closed 20 months ago
#24622 closed enhancement (fixed)
PseudoRiemannian manifods
Reported by:  egourgoulhon  Owned by:  

Priority:  major  Milestone:  sage8.2 
Component:  geometry  Keywords:  pseudoRiemannian, Riemannian, manifold, gradient, divergence, Laplacian 
Cc:  tscrim  Merged in:  
Authors:  Eric Gourgoulhon  Reviewers:  Travis Scrimshaw, John Palmieri 
Report Upstream:  N/A  Work issues:  
Branch:  185e438 (Commits)  Commit:  185e438b808c204dbf7b1f7b838fb43e40c100d2 
Dependencies:  Stopgaps: 
Description (last modified by )
This ticket implements pseudoRiemannian 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 pseudoRiemannian metric tensors are already implemented in Sage (see here), this ticket introduces
 the parent class
PseudoRiemannianManifold
, as a subclass of the existing classDifferentiableManifold
, with the specific methodsmetric
andvolume_form
 new methods
gradient
,laplacian
anddalembertian
for scalar fields  new methods
divergence
,laplacian
anddalembertian
for tensor fields  new methods
curl
,dot_product
,cross_product
andnorm
for vector fields
For a greater generality, all these methods have an optional argument metric
; if it is omitted, the metric of the underlying pseudoRiemannian 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 pseudoRiemannian 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 followup ticket #24623 implements Euclidean spaces.
This work is part of the SageManifolds project, see #18528 for an overview.
Change History (28)
comment:1 Changed 22 months ago by
 Branch set to public/manifolds/pseudoRiemannian
 Commit set to 06f8fd34981fb8b201134439a55ecf79f962a5c9
comment:2 Changed 22 months ago by
 Description modified (diff)
comment:3 Changed 22 months ago by
 Description modified (diff)
comment:4 Changed 22 months ago by
 Commit changed from 06f8fd34981fb8b201134439a55ecf79f962a5c9 to 55f356c2ee79026349a821dccd409d0d5a76718c
Branch pushed to git repo; I updated commit sha1. New commits:
55f356c  Improve documentation of pseudoRiemannian manifolds

comment:5 Changed 22 months ago by
 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 pseudoRiemannian manifolds

comment:6 Changed 22 months ago by
 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 pseudoRiemannian manifolds

comment:7 Changed 22 months ago by
 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 22 months ago by
 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 22 months ago by
 Description modified (diff)
comment:10 Changed 22 months ago by
 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 22 months ago by
 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 pseudoRiemannian manifolds

comment:12 Changed 22 months ago by
 Commit changed from 38e8fd3d9ab08783ec58dc973b3fb5575a3b79a2 to 8309fdd68066fd62b180f95be415f02ff2f7895e
Branch pushed to git repo; I updated commit sha1. New commits:
8309fdd  Improve documentation for operators on pseudoRiemannian manifolds

comment:13 Changed 22 months ago by
 Description modified (diff)
comment:14 Changed 22 months ago by
 Cc tscrim added
 Status changed from new to needs_review
comment:15 followup: ↓ 16 Changed 21 months ago by
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 sagedevel to see if anyone has any objections with adding these to the global namespace and about them being a simple redirect. (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: if 'grad' not in get_globals(): from sage.manifolds.differentiable.operators import (grad, div, curl, laplacian, dalembertian) set_global('grad', grad) 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.
Other small comments:
This is underindetented:

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 b class TensorField(ModuleElement): 3087 3087 3088 3088 .. MATH:: 3089 3089 3090 (T^\sharp)^{a_1\ldots a_{k+1}}_{\qquad\ \b_1 \ldots b_{l1}}3091 3092 T^{a_1\ldots a_k}_{\qquad\b_1 \ldots b_{pk} \, i \, b_{pk+1}\ldots b_{l1}},3090 (T^\sharp)^{a_1\ldots a_{k+1}}_{\phantom{a_1\ldots a_{k+1}}\, b_1 \ldots b_{l1}} 3091 = g^{a_{k+1} i} \, 3092 T^{a_1\ldots a_k}_{\phantom{a_1\ldots a_k}\, b_1 \ldots b_{pk} \, i \, b_{pk+1}\ldots b_{l1}}, 3093 3093 3094 3094 `g^{ab}` being the components of the inverse metric. 3095 3095 … … class TensorField(ModuleElement): 3235 3235 3236 3236 .. MATH:: 3237 3237 3238 (T^\flat)^{a_1\ldots a_{k1}}_{\qquad\ \b_1 \ldots b_{l+1}}3239 3240 T^{a_1\ldots a_{p} \, i \, a_{p+1}\ldots a_{k1}}_{\qquad\qquad\quad\;b_2 \ldots b_{l+1}},3238 (T^\flat)^{a_1\ldots a_{k1}}_{\phantom{a_1\ldots a_{k1}}\, b_1 \ldots b_{l+1}} 3239 = g_{b_1 i} \, 3240 T^{a_1\ldots a_{p} \, i \, a_{p+1}\ldots a_{k1}}_{\phantom{a_1\ldots a_{p} \, i \, a_{p+1}\ldots a_{k1}}\, b_2 \ldots b_{l+1}}, 3241 3241 3242 3242 `g_{ab}` being the components of the metric tensor. 3243 3243
(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 ; followup: ↓ 17 Changed 21 months ago by
Replying to tscrim:
Thanks for looking to this ticket and for your comments.
The biggest issue I have with this ticket is the addition of functions to the global namespace.
curl
,laplacian
, anddalembertian
I think are okay.grad
overgradient
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.
 https://en.wikipedia.org/wiki/Vector_calculus#Differential_operators
 https://en.wikipedia.org/wiki/Vector_calculus_identities#Operator_notations
 https://en.wikipedia.org/wiki/Divergence
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 sagedevel to see if anyone has any objections with adding these to the global namespace and about them being a simple redirect.
OK I will.
In the same vein, this is bad to me:
# Import differential operators in the user global namespace: if 'grad' not in get_globals(): from sage.manifolds.differentiable.operators import (grad, div, curl, laplacian, dalembertian) set_global('grad', grad) 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 pseudoRiemannian manifold? This would indeed be a good reason to have the operators in the global namespace at start.
This is underindetented: (It's okay that not everything in a
.. MATH::
block, but I do prefer the >= 4 spaces indentation visually.)
OK, I will correct this.
comment:17 in reply to: ↑ 16 ; followup: ↓ 18 Changed 21 months ago by
Replying to egourgoulhon:
Replying to tscrim:
Thanks for looking to this ticket and for your comments.
The biggest issue I have with this ticket is the addition of functions to the global namespace.
curl
,laplacian
, anddalembertian
I think are okay.grad
overgradient
I am not sure about.div
looks too much like it is coming from "divide" or "division".I agree that
div
may evoke "division", howevergrad
anddiv
are pretty much standard notations in both elementary vector calculus and differential geometry, see e.g.
 https://en.wikipedia.org/wiki/Vector_calculus#Differential_operators
 https://en.wikipedia.org/wiki/Vector_calculus_identities#Operator_notations
 https://en.wikipedia.org/wiki/Divergence
As a side note, neither
grad
nordiv
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: if 'grad' not in get_globals(): from sage.manifolds.differentiable.operators import (grad, div, curl, laplacian, dalembertian) set_global('grad', grad) 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 pseudoRiemannian 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 21 months ago by
Replying to tscrim:
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 agrad
) and all of a sudden, yourrot
computation is gone. On the other side, what if we add a differentgrad
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.
I'll think about this, given that the discussion on sagedevel leans toward not adding new stuff in the global namespace.
comment:19 Changed 21 months ago by
 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 21 months ago by
Following the conclusions of the sagedevel 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.
comment:21 followup: ↓ 24 Changed 21 months ago by
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 followup: ↓ 25 Changed 21 months ago by
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 b PseudoRiemannian Manifolds 4 4 A *pseudoRiemannian manifold* is a pair `(M,g)` where `M` is a real 5 5 differentiable manifold `M` (see 6 6 :class:`~sage.manifolds.differentiable.manifold.DifferentiableManifold`) 7 and `g` is a field nondegenerate symmetric bilinear forms on `M`, which is7 and `g` is a field of nondegenerate symmetric bilinear forms on `M`, which is 8 8 called the *metric tensor*, or simply the *metric* (see 9 9 :class:`~sage.manifolds.differentiable.metric.PseudoRiemannianMetric`). 10 10 … … We get the metric defining the Riemannian structure by:: 58 58 sage: g 59 59 Riemannian metric g on the 2dimensional Riemannian manifold S^2 60 60 61 At this stage, the metric `g` is defined a Python object but there remains to61 At this stage, the metric `g` is defined as a Python object but there remains to 62 62 initialize it by setting its components with respect to the vector frames 63 63 associated with the stereographic coordinates. Let us begin with the frame 64 64 of chart ``stereoN``:: … … manifold, we can get the metric on it via the method ``metric()``:: 145 145 sage: gU.display() 146 146 g = 4/(x^2 + y^2 + 1)^2 dx*dx + 4/(x^2 + y^2 + 1)^2 dy*dy 147 147 148 O ncourse, ``gU`` is nothing but the restriction of `g` to `U`::148 Of course, ``gU`` is nothing but the restriction of `g` to `U`:: 149 149 150 150 sage: gU is g.restrict(U) 151 151 True … … On course, ``gU`` is nothing but the restriction of `g` to `U`:: 153 153 .. RUBRIC:: Example 2: Minkowski spacetime as a Lorentzian manifold of 154 154 dimension 4 155 155 156 We start by declaring 4dimensional Lorentzian manifold::156 We start by declaring a 4dimensional Lorentzian manifold:: 157 157 158 158 sage: M = Manifold(4, 'M', structure='Lorentzian') 159 159 sage: M … … class PseudoRiemannianManifold(DifferentiableManifold): 223 223 A *pseudoRiemannian manifold* is a pair `(M,g)` where `M` is a real 224 224 differentiable manifold `M` (see 225 225 :class:`~sage.manifolds.differentiable.manifold.DifferentiableManifold`) 226 and `g` is a field nondegenerate symmetric bilinear forms on `M`, which is226 and `g` is a field of nondegenerate symmetric bilinear forms on `M`, which is 227 227 called the *metric tensor*, or simply the *metric* (see 228 228 :class:`~sage.manifolds.differentiable.metric.PseudoRiemannianMetric`). 229 229 … … class PseudoRiemannianManifold(DifferentiableManifold): 405 405 dest_map=None): 406 406 r""" 407 407 Return the metric giving the pseudoRiemannian structure to the 408 manifold, or define sa new metric tensor on the manifold.408 manifold, or define a new metric tensor on the manifold. 409 409 410 410 INPUT: 411 411
comment:23 Changed 21 months ago by
 Commit changed from 18b63a6de6dcceed8b29edc339d8e301785b5a03 to 185e438b808c204dbf7b1f7b838fb43e40c100d2
Branch pushed to git repo; I updated commit sha1. New commits:
185e438  Improve documentation of pseudoRiemannian manifolds

comment:24 in reply to: ↑ 21 Changed 21 months ago by
Replying to tscrim:
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
andcurl
, etc. Also, do you want to linklaplacition()
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 21 months ago by
Replying to jhpalmieri:
A few typos with proposed corrections:
Thank you very much for these corrections. They are effective in the above commit.
comment:26 Changed 21 months ago by
 Reviewers set to Travis Scrimshaw, John Palmieri
 Status changed from needs_review to positive_review
LGTM. Thank you.
comment:27 Changed 21 months ago by
Thank you very much for the review!
comment:28 Changed 20 months ago by
 Branch changed from public/manifolds/pseudoRiemannian to 185e438b808c204dbf7b1f7b838fb43e40c100d2
 Resolution set to fixed
 Status changed from positive_review to closed
This is work in progress...
New commits:
First version of pseudoRiemannian manifold class
PseudoRiemannian manifolds constructed by the generic function Manifold
Divergence of a tensor field + new section on pseudoRiemannian manifolds in the reference manual
Add doctests for pseudoRiemannian manifolds