# Differential Geometry Module¶

## Base Class Reference¶

class sympy.diffgeom.Manifold(name, dim)

Object representing a mathematical manifold.

The only role that this object plays is to keep a list of all patches defined on the manifold. It does not provide any means to study the topological characteristics of the manifold that it represents.

class sympy.diffgeom.Patch(name, manifold)

Object representing a patch on a manifold.

On a manifold one can have many patches that do not always include the whole manifold. On these patches coordinate charts can be defined that permit the parametrization of any point on the patch in terms of a tuple of real numbers (the coordinates).

This object serves as a container/parent for all coordinate system charts that can be defined on the patch it represents.

Examples:

Define a Manifold and a Patch on that Manifold: >>> from sympy.diffgeom import Manifold, Patch >>> m = Manifold(‘M’, 3) >>> p = Patch(‘P’, m) >>> p in m.patches True

class sympy.diffgeom.CoordSystem(name, patch, names=None)

Contains all coordinate transformation logic.

Examples

Define a Manifold and a Patch, and then define two coord systems on that patch:

>>> from sympy import symbols, sin, cos, pi
>>> from sympy.diffgeom import Manifold, Patch, CoordSystem
>>> r, theta = symbols('r, theta')
>>> m = Manifold('M', 2)
>>> patch = Patch('P', m)
>>> rect = CoordSystem('rect', patch)
>>> polar = CoordSystem('polar', patch)
>>> rect in patch.coord_systems
True


Connect the coordinate systems. An inverse transformation is automatically found by solve when possible:

>>> polar.connect_to(rect, [r, theta], [r*cos(theta), r*sin(theta)])
>>> polar.coord_tuple_transform_to(rect, [0, 2])
[0]
[0]
>>> polar.coord_tuple_transform_to(rect, [2, pi/2])
[0]
[2]
>>> rect.coord_tuple_transform_to(polar, [1, 1])
[sqrt(2)]
[   pi/4]


Calculate the jacobian of the polar to cartesian transformation:

>>> polar.jacobian(rect, [r, theta])
[cos(theta), -r*sin(theta)]
[sin(theta),  r*cos(theta)]


Define a point using coordinates in one of the coordinate systems:

>>> p = polar.point([1, 3*pi/4])
>>> rect.point_to_coords(p)
[-sqrt(2)/2]
[ sqrt(2)/2]


Define a basis scalar field (i.e. a coordinate function), that takes a point and returns its coordinates. It is an instance of BaseScalarField.

>>> rect.coord_function(0)(p)
-sqrt(2)/2
>>> rect.coord_function(1)(p)
sqrt(2)/2


Define a basis vector field (i.e. a unit vector field along the coordinate line). Vectors are also differential operators on scalar fields. It is an instance of BaseVectorField.

>>> v_x = rect.base_vector(0)
>>> x = rect.coord_function(0)
>>> v_x(x)(p)
1
>>> v_x(v_x(x))(p)
0


Define a basis oneform field:

>>> dx = rect.base_oneform(0)
>>> dx(v_x)(p)
1


If you provide a list of names the fields will print nicely: - without provided names:

>>> x, v_x, dx
(rect_0, e_rect_0, drect_0)

• with provided names
>>> rect = CoordSystem('rect', patch, ['x', 'y'])
>>> rect.coord_function(0), rect.base_vector(0), rect.base_oneform(0)
(x, e_x, dx)

base_oneform(coord_index)

Return a basis 1-form field.

The basis one-form field for this coordinate system. It is also an operator on vector fields.

See the docstring of CoordSystem for examples.

base_oneforms()

Returns a list of all base oneforms.

For more details see the base_oneform method of this class.

base_vector(coord_index)

Return a basis vector field.

The basis vector field for this coordinate system. It is also an operator on scalar fields.

See the docstring of CoordSystem for examples.

base_vectors()

Returns a list of all base vectors.

For more details see the base_vector method of this class.

connect_to(to_sys, from_coords, to_exprs, inverse=True, fill_in_gaps=False)

Register the transformation used to switch to another coordinate system.

Parameters : to_sys : another instance of CoordSystem from_coords : list of symbols in terms of which to_exprs is given to_exprs : list of the expressions of the new coordinate tuple inverse : try to deduce and register the inverse transformation fill_in_gaps : try to deduce other transformation that are made possible by composing the present transformation with other already registered transformation
coord_function(coord_index)

Return a BaseScalarField that takes a point and returns one of the coords.

Takes a point and returns its coordinate in this coordinate system.

See the docstring of CoordSystem for examples.

coord_functions()

Returns a list of all coordinate functions.

For more details see the coord_function method of this class.

coord_tuple_transform_to(to_sys, coords)

Transform coords to coord system to_sys.

See the docstring of CoordSystem for examples.

jacobian(to_sys, coords)

Return the jacobian matrix of a transformation.

point(coords)

Create a Point with coordinates given in this coord system.

See the docstring of CoordSystem for examples.

point_to_coords(point)

Calculate the coordinates of a point in this coord system.

See the docstring of CoordSystem for examples.

class sympy.diffgeom.BaseScalarField(coord_sys, index)

Base Scalar Field over a Manifold for a given Coordinate System.

A scalar field takes a point as an argument and returns a scalar.

A base scalar field of a coordinate system takes a point and returns one of the coordinates of that point in the coordinate system in question.

To define a scalar field you need to choose the coordinate system and the index of the coordinate.

The use of the scalar field after its definition is independent of the coordinate system in which it was defined, however due to limitations in the simplification routines you may arrive at more complicated expression if you use unappropriate coordinate systems.

You can build complicated scalar fields by just building up SymPy expressions containing BaseScalarField instances.

Examples

Define boilerplate Manifold, Patch and coordinate systems:

>>> from sympy import symbols, sin, cos, pi, Function
>>> from sympy.diffgeom import (
...        Manifold, Patch, CoordSystem, Point, BaseScalarField)
>>> r0, theta0 = symbols('r0, theta0')
>>> m = Manifold('M', 2)
>>> p = Patch('P', m)
>>> rect = CoordSystem('rect', p)
>>> polar = CoordSystem('polar', p)
>>> polar.connect_to(rect, [r0, theta0], [r0*cos(theta0), r0*sin(theta0)])


Point to be used as an argument for the filed:

>>> point = polar.point([r0, 0])


Examples of fields:

>>> fx = BaseScalarField(rect, 0)
>>> fy = BaseScalarField(rect, 1)
>>> (fx**2+fy**2)(point)
r0**2

>>> g = Function('g')
>>> ftheta = BaseScalarField(polar, 1)
>>> fg = g(ftheta-pi)
>>> fg(point)
g(-pi)

class sympy.diffgeom.BaseVectorField(coord_sys, index)

Vector Field over a Manifold.

A vector field is an operator taking a scalar field and returning a directional derivative (which is also a scalar field).

A base vector field is the same type of operator, however the derivation is specifically done wrt a chosen coordinate.

To define a base vector field you need to choose the coordinate system and the index of the coordinate.

The use of the vector field after its definition is independent of the coordinate system in which it was defined, however due to limitations in the simplification routines you may arrive at more complicated expression if you use unappropriate coordinate systems.

Examples

Use the predefined R2 manifold, setup some boilerplate.

>>> from sympy import symbols, pi, Function
>>> from sympy.diffgeom.rn import R2, R2_p, R2_r
>>> from sympy.diffgeom import BaseVectorField
>>> from sympy import pprint
>>> x0, y0, r0, theta0 = symbols('x0, y0, r0, theta0')


Points to be used as arguments for the field:

>>> point_p = R2_p.point([r0, theta0])
>>> point_r = R2_r.point([x0, y0])


Scalar field to operate on:

>>> g = Function('g')
>>> s_field = g(R2.x, R2.y)
>>> s_field(point_r)
g(x0, y0)
>>> s_field(point_p)
g(r0*cos(theta0), r0*sin(theta0))


Vector field:

>>> v = BaseVectorField(R2_r, 1)
>>> pprint(v(s_field))
/  d              \|
|-----(g(x, xi_2))||
\dxi_2            /|xi_2=y
>>> pprint(v(s_field)(point_r).doit())
d
---(g(x0, y0))
dy0
>>> pprint(v(s_field)(point_p).doit())
/  d                           \|
|-----(g(r0*cos(theta0), xi_2))||
\dxi_2                         /|xi_2=r0*sin(theta0)

class sympy.diffgeom.Differential(form_field)

Return the differential (exterior derivative) of a form field.

The differential of a form (i.e. the exterior derivative) has a complicated definition in the general case.

The differential $$df$$ of the 0-form $$f$$ is defined for any vector field $$v$$ as $$df(v) = v(f)$$.

Examples

Use the predefined R2 manifold, setup some boilerplate.

>>> from sympy import Function
>>> from sympy.diffgeom.rn import R2
>>> from sympy.diffgeom import Differential
>>> from sympy import pprint


Scalar field (0-forms):

>>> g = Function('g')
>>> s_field = g(R2.x, R2.y)


Vector fields:

>>> e_x, e_y, = R2.e_x, R2.e_y


Differentials:

>>> dg = Differential(s_field)
>>> dg
d(g(x, y))
>>> pprint(dg(e_x))
/  d              \|
|-----(g(xi_1, y))||
\dxi_1            /|xi_1=x
>>> pprint(dg(e_y))
/  d              \|
|-----(g(x, xi_2))||
\dxi_2            /|xi_2=y


Applying the exterior derivative operator twice always results in:

>>> Differential(dg)
0

class sympy.diffgeom.BaseCovarDerivativeOp(coord_sys, index, christoffel)

Covariant derivative operator wrt a base vector.

Examples

>>> from sympy.diffgeom.rn import R2, R2_r
>>> from sympy.diffgeom import BaseCovarDerivativeOp
>>> from sympy.diffgeom import metric_to_Christoffel_2nd, TensorProduct
>>> TP = TensorProduct
>>> ch = metric_to_Christoffel_2nd(TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy))
>>> ch
(((0, 0), (0, 0)), ((0, 0), (0, 0)))
>>> cvd = BaseCovarDerivativeOp(R2_r, 0, ch)
>>> cvd(R2.x)
1
>>> cvd(R2.x*R2.e_x)
e_x

class sympy.diffgeom.CovarDerivativeOp(wrt, christoffel)

Covariant derivative operator.

Examples

>>> from sympy.diffgeom.rn import R2
>>> from sympy.diffgeom import CovarDerivativeOp
>>> from sympy.diffgeom import metric_to_Christoffel_2nd, TensorProduct
>>> TP = TensorProduct
>>> ch = metric_to_Christoffel_2nd(TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy))
>>> ch
(((0, 0), (0, 0)), ((0, 0), (0, 0)))
>>> cvd = CovarDerivativeOp(R2.x*R2.e_x, ch)
>>> cvd(R2.x)
x
>>> cvd(R2.x*R2.e_x)
x*e_x