Opened 5 years ago

Closed 5 years ago

# Deprecate CoordinatePatch and DifferentialForm to keep a single version of differential forms

Reported by: Owned by: egourgoulhon major sage-8.2 geometry manifolds, differential forms jvkersch, tscrim, niles, jason, mhampton Eric Gourgoulhon Travis Scrimshaw N/A 520ee73 520ee7315fbd2dfddd62f2add42e2f7e012b518b

At present differential forms are dealt with by different and incompatible parts of Sage: the CoordinatePatch version (implemented in #9650) and the manifold version (implemented in #18843).

All functionalities of the CoordinatePatch version (like wedge product and exterior derivative) are implemented in the manifold version, but the manifold one is more recent and provides more functionalities, like

• better display capabilities
• changing the coordinates (the CoordinatePatch version assumes a fixed coordinate system)
• evaluating the Lie derivative with respect to a vector field
• performing the interior product with a p-vector
• evaluating the Hodge dual with respect to a metric

It is also more flexible:

• the indices may be chosen to start from 1 (or any other value) instead of 0
• one may use index notation with Einstein convention of summation on repeated indices
• the base ring is not limited to the Symbolic Ring.

As this ask.sagemath question reveals, keeping both versions is confusing and the current ticket is devoted to deprecate the CoordinatePatch version.

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

Illustration of similarities and differences

Let us declare a differential form of degree 2 with the CoordinatePatch version:

```sage: x, y, z = var('x, y, z')
sage: U = CoordinatePatch((x, y, z))
sage: F = DifferentialForms(U)
sage: f = DifferentialForm(F, 2)
sage: f[0,1] = x*sin(z)
sage: f[1,2] = y*z
sage: f
x*sin(z)*dx/\dy + y*z*dy/\dz
```

To perform the same thing with the manifold version, one should write (using a different Sage session to avoid any confusion):

```sage: U = Manifold(3, 'U')
sage: X.<x,y,z> = U.chart()
sage: f = U.diff_form(2, 'f')
sage: f[0,1] = x*sin(z)
sage: f[1,2] = y*z
sage: f
2-form f on the 3-dimensional differentiable manifold U
sage: f.display()
f = x*sin(z) dx/\dy + y*z dy/\dz
```

Let us introduce another differential form, as a 1-form; in the CoordinatePatch version:

```sage: g = DifferentialForm(F, 1)
sage: g[0], g[1], g[2] = (y^2, -z, 2*x-y)
sage: g
(2*x - y)*dz + y^2*dx + -z*dy
```

In the manifold version, one may use the shortcut notation `g[:]` to set the components of `g`:

```sage: g = U.diff_form(1, 'g')
sage: g[:] = (y^2, -z, 2*x-y)
sage: g.display()
g = y^2 dx - z dy + (2*x - y) dz
```

The wedge product of `f` by `g` is obtained in the same way in both methods: for CoordinatePatch:

```sage: f.wedge(g)
(y^3*z + (2*x - y)*x*sin(z))*dx/\dy/\dz
```

while for the manifold version:

```sage: f.wedge(g)
3-form f/\g on the 3-dimensional differentiable manifold U
sage: f.wedge(g).display()
f/\g = (y^3*z + (2*x^2 - x*y)*sin(z)) dx/\dy/\dz
```

The exterior derivative is computed via the method `diff()` in the CoordinatePatch version:

```sage: f.diff()
x*cos(z)*dx/\dy/\dz
```

and via the method `exterior_derivative()` in the manifold version:

```sage: f.exterior_derivative().display()
df = x*cos(z) dx/\dy/\dz
```

A shortcut is provided by the function `xder`, to be used as the operator d to compute df:

```sage: from sage.manifolds.utilities import xder
sage: xder(f) == f.exterior_derivative()
True
```

A difference regards the parents: in the CoordinatePatch version, the 2-form `f` and the 1-form `g` have the same parent, which is the graded algebra Omega(U) of all differential forms defined on U, and declared as `F = DifferentialForms(U)` at the beginning of the session:

```sage: f.parent()
Algebra of differential forms in the variables x, y, z
sage: f.parent() is F
True
sage: g.parent() is F
True
```

In the manifold case, the parent of `f` is the set Omega2(U) of 2-forms on U, which is considered as a free module of rank 3 on the algebra Coo(U) of scalar fields on U, while the parent of `g` is the set Omega1(U) of 1-forms on U, which is considered as another free module of rank 3 on Coo(U):

```sage: f.parent()
Free module Omega^2(U) of 2-forms on the 3-dimensional differentiable manifold U
sage: f.parent().base_ring()
Algebra of differentiable scalar fields on the 3-dimensional differentiable manifold U
sage: f.parent().rank()
3
sage: g.parent()
Free module Omega^1(U) of 1-forms on the 3-dimensional differentiable manifold U
sage: g.parent().rank()
3
```

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

Examples of functionalities avalaible only in the manifold version

The capability to access directly to the coordinate basis 1-forms:

```sage: X.coframe()
Coordinate coframe (U, (dx,dy,dz))
sage: dx = X.coframe()[0]
sage: dy = X.coframe()[1]
sage: a = sin(z)*dx.wedge(dy)
sage: a.display()
sin(z) dx/\dy
```

The interior product with a vector field:

```sage: v = U.vector_field('v')
sage: v[:] = (-y, z, x^2)
sage: v.interior_product(f)
1-form i_v f on the 3-dimensional differentiable manifold U
sage: v.interior_product(f).display()
i_v f = -x*z*sin(z) dx + (-x^2*y*z - x*y*sin(z)) dy + y*z^2 dz
```

The Lie derivative with respect to a vector field:

```sage: f.lie_derivative(v)
2-form on the 3-dimensional differentiable manifold U
sage: f.lie_derivative(v).display()
(x^3*cos(z) - 2*x*y*z - y*sin(z)) dx/\dy + x*sin(z) dx/\dz + (x^2*y + z^2) dy/\dz
```

As an illustration, we may check that Cartan's identity Liev f = d(iv f) + iv df holds:

```sage: f.lie_derivative(v) == (v.interior_product(f)).exterior_derivative() + \
....:                        v.interior_product(f.exterior_derivative())
True
```

Computing the Hodge dual with respect to a given metric:

```sage: h = U.metric('h')
sage: h[0,0] = 1+y^2
sage: h[1,1] = 1+z^2
sage: h[2,2] = 1+x^2
sage: h.display()
h = (y^2 + 1) dx*dx + (z^2 + 1) dy*dy + (x^2 + 1) dz*dz
sage: f.hodge_dual(h)
1-form *f on the 3-dimensional differentiable manifold U
sage: f.hodge_dual(h).display()
*f = sqrt(y^2 + 1)*y*z/(sqrt(x^2 + 1)*sqrt(z^2 + 1)) dx + sqrt(x^2 + 1)*x*sin(z)/(sqrt(y^2 + 1)*sqrt(z^2 + 1)) dz
```

Computing new components under a change of coordinates:

```sage: X2.<u,v,w> = U.chart()
sage: X_to_X2 = X.transition_map(X2, [y+z, z+x, x+y])
sage: X_to_X2.inverse()
Change of coordinates from Chart (U, (u, v, w)) to Chart (U, (x, y, z))
sage: g.display()  # the default for g.display(X.frame(), X)
g = y^2 dx - z dy + (2*x - y) dz
sage: g.display(X2.frame(), X2)
g = (-1/8*u^2 + 1/4*(u + 2)*v - 1/8*v^2 - 1/4*(u - v - 2)*w - 1/8*w^2 - u) du + (1/8*u^2 - 1/4*(u - 4)*v + 1/8*v^2 + 1/4*(u - v)*w + 1/8*w^2 - 1/2*u) dv + (1/8*u^2 - 1/4*(u + 4)*v + 1/8*v^2 + 1/4*(u - v)*w + 1/8*w^2 + 1/2*u) dw
```

Using the function `display_comp`, which is more convenient for lengthy expressions:

```sage: g.display_comp()   # the default for g.display_comp(X.frame(), X)
g_x = y^2
g_y = -z
g_z = 2*x - y
sage: g.display_comp(X2.frame(), X2)
g_u = -1/8*u^2 + 1/4*(u + 2)*v - 1/8*v^2 - 1/4*(u - v - 2)*w - 1/8*w^2 - u
g_v = 1/8*u^2 - 1/4*(u - 4)*v + 1/8*v^2 + 1/4*(u - v)*w + 1/8*w^2 - 1/2*u
g_w = 1/8*u^2 - 1/4*(u + 4)*v + 1/8*v^2 + 1/4*(u - v)*w + 1/8*w^2 + 1/2*u
```

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

Regarding the code, both versions share the same trick for the storage of components: a dictionary whose keys are the indices, limited to nonredundant ones (i.e. only the components that cannot be deduced by antisymmetry). For the CoordinatePatch version and the same example as above, we have

```sage: f
x*sin(z)*dx/\dy + y*z*dy/\dz
sage: f._components
{(0, 1): x*sin(z), (1, 2): y*z}
sage: f[1,0]  # a component not stored but deduced by antisymmetry
-x*sin(z)
```

while for the manifold version, we have

```sage: f.display()
f = x*sin(z) dx/\dy + y*z dy/\dz
sage: f.components()
Fully antisymmetric 2-indices components w.r.t. Coordinate frame (U, (d/dx,d/dy,d/dz))
sage: f.components()._comp
{(0, 1): Scalar field on the 3-dimensional differentiable manifold U,
(1, 2): Scalar field on the 3-dimensional differentiable manifold U}
sage: for i, c in f.components()._comp.items():
....:     print("{}: {}".format(i, c.expr()))
....:
(0, 1): x*sin(z)
(1, 2): y*z
sage: f[1,0]  # a component not stored but deduced by antisymmetry
-x*sin(z)
```

Actually, the storage method of the CoordinatePatch version inspired the manifold one ;-), as acknowledged in the AUTHORS section of the documentation.

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

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

• Description modified (diff)

### comment:5 Changed 5 years ago by egourgoulhon

• Description modified (diff)

### comment:6 Changed 5 years ago by egourgoulhon

• Authors set to Eric Gourgoulhon
• Branch set to public/manifolds/deprecate_DifferentialForm-24444
• Cc jvkersch tscrim niles jason mhampton added

New commits:

 ​520ee73 `Deprecate CoordinatePatch and DifferentialForm (trac #24444)`

### comment:7 Changed 5 years ago by egourgoulhon

• Status changed from new to needs_review

The deprecation is implemented in the attached branch. Please review.

### comment:8 follow-up: ↓ 9 Changed 5 years ago by tscrim

• Reviewers set to Travis Scrimshaw
• Status changed from needs_review to positive_review
• Type changed from defect to enhancement

LGTM.

### comment:9 in reply to: ↑ 8 Changed 5 years ago by egourgoulhon

Thanks for the review!

### comment:10 Changed 5 years ago by vbraun

• Branch changed from public/manifolds/deprecate_DifferentialForm-24444 to 520ee7315fbd2dfddd62f2add42e2f7e012b518b
• Resolution set to fixed
• Status changed from positive_review to closed
Note: See TracTickets for help on using tickets.