Opened 10 months ago

Closed 9 months ago

#24622 closed enhancement (fixed)

Pseudo-Riemannian manifods

Reported by: egourgoulhon Owned by:
Priority: major Milestone: sage-8.2
Component: geometry Keywords: pseudo-Riemannian, 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 egourgoulhon)

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.

Change History (28)

comment:1 Changed 10 months ago by egourgoulhon

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

This is work in progress...


New commits:

8e1148cFirst version of pseudo-Riemannian manifold class
8e56cf3Pseudo-Riemannian manifolds constructed by the generic function Manifold
ce3a617Divergence of a tensor field + new section on pseudo-Riemannian manifolds in the reference manual
06f8fd3Add doctests for pseudo-Riemannian manifolds

comment:2 Changed 10 months ago by egourgoulhon

  • Description modified (diff)

comment:3 Changed 10 months ago by egourgoulhon

  • Description modified (diff)

comment:4 Changed 10 months ago by git

  • Commit changed from 06f8fd34981fb8b201134439a55ecf79f962a5c9 to 55f356c2ee79026349a821dccd409d0d5a76718c

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

55f356cImprove documentation of pseudo-Riemannian manifolds

comment:5 Changed 10 months ago by git

  • Commit changed from 55f356c2ee79026349a821dccd409d0d5a76718c to 0fc661a5beaf076fdf67e0d4f45b546ed8e23e8e

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

0fc661aRemove method set_metric and improve doc of pseudo-Riemannian manifolds

comment:6 Changed 10 months ago by git

  • Commit changed from 0fc661a5beaf076fdf67e0d4f45b546ed8e23e8e to b4dddf74279a21aa9cc645f959c8cd6b513a8d48

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

b4dddf7Add operators Laplacian, d'Alembertian and curl on pseudo-Riemannian manifolds

comment:7 Changed 10 months ago by git

  • Commit changed from b4dddf74279a21aa9cc645f959c8cd6b513a8d48 to 040b01c35f3082b4788bdeefea9d28aa1f96d3bc

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

040b01cAdd dot product and cross product of vector fields

comment:8 Changed 10 months ago by git

  • Commit changed from 040b01c35f3082b4788bdeefea9d28aa1f96d3bc to 46b8f66385cd1c34e5310d627a0e44983f87cc4a

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

46b8f66Add norm of vector fields.

comment:9 Changed 10 months ago by egourgoulhon

  • Description modified (diff)

comment:10 Changed 10 months ago by git

  • Commit changed from 46b8f66385cd1c34e5310d627a0e44983f87cc4a to 135af976131baf0d1551806a7be1be25ef0e06c0

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

135af97Add method volume_form() to class PseudoRiemannianManifold

comment:11 Changed 10 months ago by git

  • Commit changed from 135af976131baf0d1551806a7be1be25ef0e06c0 to 38e8fd3d9ab08783ec58dc973b3fb5575a3b79a2

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

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

comment:12 Changed 10 months ago by git

  • Commit changed from 38e8fd3d9ab08783ec58dc973b3fb5575a3b79a2 to 8309fdd68066fd62b180f95be415f02ff2f7895e

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

8309fddImprove documentation for operators on pseudo-Riemannian manifolds

comment:13 Changed 10 months ago by egourgoulhon

  • Description modified (diff)

comment:14 Changed 10 months ago by egourgoulhon

  • Cc tscrim added
  • Status changed from new to needs_review

comment:15 follow-up: Changed 10 months 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:
        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 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 b class TensorField(ModuleElement): 
    30873087
    30883088        .. MATH::
    30893089
    3090             (T^\sharp)^{a_1\ldots a_{k+1}}_{\qquad\ \ b_1 \ldots b_{l-1}}
    3091             = g^{a_{k+1} i} \,
    3092             T^{a_1\ldots a_k}_{\qquad\  b_1 \ldots b_{p-k} \, i \, b_{p-k+1}\ldots b_{l-1}},
     3090          (T^\sharp)^{a_1\ldots a_{k+1}}_{\phantom{a_1\ldots a_{k+1}}\, b_1 \ldots b_{l-1}}
     3091          = g^{a_{k+1} i} \,
     3092          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}},
    30933093
    30943094        `g^{ab}` being the components of the inverse metric.
    30953095
    class TensorField(ModuleElement): 
    32353235
    32363236        .. MATH::
    32373237
    3238             (T^\flat)^{a_1\ldots a_{k-1}}_{\qquad\ \ b_1 \ldots b_{l+1}}
    3239             = g_{b_1 i} \,
    3240             T^{a_1\ldots a_{p} \, i \, a_{p+1}\ldots a_{k-1}}_{\qquad\qquad\quad\; b_2 \ldots b_{l+1}},
     3238          (T^\flat)^{a_1\ldots a_{k-1}}_{\phantom{a_1\ldots a_{k-1}}\, b_1 \ldots b_{l+1}}
     3239          = g_{b_1 i} \,
     3240          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}},
    32413241
    32423242        `g_{ab}` being the components of the metric tensor.
    32433243

(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: Changed 9 months ago by 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, 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:
        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 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 9 months ago by egourgoulhon (previous) (diff)

comment:17 in reply to: ↑ 16 ; follow-up: Changed 9 months ago by tscrim

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, 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:
        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 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 9 months ago by egourgoulhon

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 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.

I'll think about this, given that the discussion on sage-devel leans toward not adding new stuff in the global namespace.

comment:19 Changed 9 months ago by git

  • Commit changed from 8309fdd68066fd62b180f95be415f02ff2f7895e to 18b63a6de6dcceed8b29edc339d8e301785b5a03

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

18b63a6Differential operators are no longer imported in the global namespace by PseudoRiemannianManifold.__init__

comment:20 Changed 9 months 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 9 months ago by egourgoulhon (previous) (diff)

comment:21 follow-up: Changed 9 months 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: Changed 9 months 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 b Pseudo-Riemannian Manifolds 
    44A *pseudo-Riemannian manifold* is a pair `(M,g)` where `M` is a real
    55differentiable manifold `M` (see
    66:class:`~sage.manifolds.differentiable.manifold.DifferentiableManifold`)
    7 and `g` is a field non-degenerate symmetric bilinear forms on `M`, which is
     7and `g` is a field of non-degenerate symmetric bilinear forms on `M`, which is
    88called the *metric tensor*, or simply the *metric* (see
    99:class:`~sage.manifolds.differentiable.metric.PseudoRiemannianMetric`).
    1010
    We get the metric defining the Riemannian structure by:: 
    5858    sage: g
    5959    Riemannian metric g on the 2-dimensional Riemannian manifold S^2
    6060
    61 At this stage, the metric `g` is defined a Python object but there remains to
     61At this stage, the metric `g` is defined as a Python object but there remains to
    6262initialize it by setting its components with respect to the vector frames
    6363associated with the stereographic coordinates. Let us begin with the frame
    6464of chart ``stereoN``::
    manifold, we can get the metric on it via the method ``metric()``:: 
    145145    sage: gU.display()
    146146    g = 4/(x^2 + y^2 + 1)^2 dx*dx + 4/(x^2 + y^2 + 1)^2 dy*dy
    147147
    148 On course, ``gU`` is nothing but the restriction of `g` to `U`::
     148Of course, ``gU`` is nothing but the restriction of `g` to `U`::
    149149
    150150    sage: gU is g.restrict(U)
    151151    True
    On course, ``gU`` is nothing but the restriction of `g` to `U`:: 
    153153.. RUBRIC:: Example 2: Minkowski spacetime as a Lorentzian manifold of
    154154  dimension 4
    155155
    156 We start by declaring 4-dimensional Lorentzian manifold::
     156We start by declaring a 4-dimensional Lorentzian manifold::
    157157
    158158    sage: M = Manifold(4, 'M', structure='Lorentzian')
    159159    sage: M
    class PseudoRiemannianManifold(DifferentiableManifold): 
    223223    A *pseudo-Riemannian manifold* is a pair `(M,g)` where `M` is a real
    224224    differentiable manifold `M` (see
    225225    :class:`~sage.manifolds.differentiable.manifold.DifferentiableManifold`)
    226     and `g` is a field non-degenerate symmetric bilinear forms on `M`, which is
     226    and `g` is a field of non-degenerate symmetric bilinear forms on `M`, which is
    227227    called the *metric tensor*, or simply the *metric* (see
    228228    :class:`~sage.manifolds.differentiable.metric.PseudoRiemannianMetric`).
    229229
    class PseudoRiemannianManifold(DifferentiableManifold): 
    405405               dest_map=None):
    406406        r"""
    407407        Return the metric giving the pseudo-Riemannian structure to the
    408         manifold, or defines a new metric tensor on the manifold.
     408        manifold, or define a new metric tensor on the manifold.
    409409
    410410        INPUT:
    411411

comment:23 Changed 9 months ago by git

  • Commit changed from 18b63a6de6dcceed8b29edc339d8e301785b5a03 to 185e438b808c204dbf7b1f7b838fb43e40c100d2

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

185e438Improve documentation of pseudo-Riemannian manifolds

comment:24 in reply to: ↑ 21 Changed 9 months ago by egourgoulhon

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 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 9 months ago by egourgoulhon

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 9 months ago by tscrim

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

LGTM. Thank you.

comment:27 Changed 9 months ago by egourgoulhon

Thank you very much for the review!

comment:28 Changed 9 months 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.