Computational Geometry Workshop

Wichita State University, Dept. of Mathematics

Differential Forms

Last Changed: 4 Sep 2017

Authors: Justin M. Ryan,

This notebook contains sample code related to the lecture on Differential Forms. Terse lecture notes may be found at

http://geometerjustin.com/teaching/cgw/notes/notes_02.html

So future readers know what version we're using:

In [1]:
version()
Out[1]:
'SageMath version 7.5.1, Release Date: 2017-01-15'

Force $\LaTeX$ display:

In [2]:
%display latex

Define the chart we're working in/on:

In [3]:
U = Manifold(3,'U',latex_name=r'\mathbb{U}',start_index=1);
coord.<x,y,z>=U.chart();
e = coord.frame();
de = coord.coframe();

We want to work with the differential $k$-forms on $\mathbb{U}$. We begin by defining two 1-forms on $\mathbb{U}$.

In [4]:
t1 = U.diff_form(1,latex_name=r'\theta_1',);
t1[:] =[x, 2*z-x,sin(y)];
t2 = U.diff_form(1,latex_name=r'\theta_2');
t2[:] =[0,-z,y];

We can now compute the exterior product of $\theta_1$ and $\theta_2$. The command for this is just ".wedge()". The exterior product $\theta_1 \wedge \theta_2$ is a 2-form.

In [5]:
t1w2 = t1.wedge(t2);
print(t1w2)
t1w2.display()
2-form on the 3-dimensional differentiable manifold U
Out[5]:

Exterior products are alternating.

In [6]:
t2w1 = t2.wedge(t1);
t2w1 == -t1w2
Out[6]:

The exterior derivative of a form increases the degree by 1.

In [7]:
dt1 = t1.exterior_derivative();
dt2 = t2.exterior_derivative();
print(dt1)
dt1.display()
2-form on the 3-dimensional differentiable manifold U
Out[7]:
In [8]:
print(dt2)
dt2.display()
2-form on the 3-dimensional differentiable manifold U
Out[8]:

The exterior derivative of a smooth function $f \in \mathfrak{F} = \Omega^0$ is the usual differential of $f$ from Calc III. Recall that we need to define smooth functions on $\mathbb{U}$ as scalar fields.

In [9]:
f = U.scalar_field({coord: x^2 - 2*z^(sin(y))});
df = f.exterior_derivative();
print(df)
df.display()
1-form on the 3-dimensional differentiable manifold U
Out[9]:
In [10]:
df == f.differential()
Out[10]:

Applying the exterior derivative to the same form twice always yields 0 (i.e., the form identically equal to 0).

In [11]:
ddf = df.exterior_derivative();
print(ddf)
ddf.display()
2-form on the 3-dimensional differentiable manifold U
Out[11]:
In [12]:
ddt1 = dt1.exterior_derivative();
print(ddt1)
ddt1.display()
3-form on the 3-dimensional differentiable manifold U
Out[12]:
In [13]:
ddt2 = dt2.exterior_derivative();
print(ddt2)
ddt2.display()
3-form on the 3-dimensional differentiable manifold U
Out[13]:

Differential $k$-forms map $\mathfrak{X}^k \to \mathfrak{F}$.

In [14]:
X1 = U.vector_field(latex_name=r'X_1');
X1[:] = [x,-x,2*z];
X2 = U.vector_field(latex_name=r'X_2');
X2[:] = [cos(z),-sin(z),z];
In [15]:
print(df(X1))
df(X1).display()
Scalar field on the 3-dimensional differentiable manifold U
Out[15]:

$df(X_1)$ and $X_1(f)$ coincide. In Calc III lingo, they both represent the (non-normalized) directional derivative of $f$ in the direction of $X_1$.

In [16]:
print(X1(f))
X1(f).display()
Scalar field on the 3-dimensional differentiable manifold U
Out[16]:
In [17]:
df(X1) == X1(f)
Out[17]:

$2$-forms take two vector fields as arguments.

In [18]:
dt1(X1,X2).display()
Out[18]:
In [19]:
dt1(X2,X1).display()
Out[19]:
In [20]:
dt1(X1,X2) == -dt1(X2,X1)
Out[20]:

The space $\Omega^n$ is a 1-dimensional space whose basis covector is the Euclidean volume form on $\mathbb{U}$.

In [21]:
vol = U.diff_form(3,latex_name=r'\omega');
vol[1,2,3] = 1;
In [22]:
print(vol)
3-form on the 3-dimensional differentiable manifold U
In [23]:
vol.display()
Out[23]:
In [24]:
vol(2*e[1],4*e[2],e[3])
Out[24]:
In [25]:
vol(2*e[1],4*e[2],e[3]).display()
Out[25]:
In [26]:
p=U.point((1,2,3))
In [27]:
vol(2*e[1],4*e[2],e[3])(p)
Out[27]:

The volume form can be used to calculate the determinant of a linear transformation of $T\mathbb{U}$. By a linear transformation of $T\mathbb{U}$, we mean a linear transformation of each tangent space that varies smoothly between tangent spaces. We call such a map a tangent-space automorphism field on $\mathbb{U}$.

In [28]:
A = U.automorphism_field('aut',latex_name=r'A');
A[e,:] = [[1,x,z],[0,3,y],[0,0,5]];
print(A)
A.display()
Field of tangent-space automorphisms aut on the 3-dimensional differentiable manifold U
Out[28]:
In [29]:
A.display_comp()
Out[29]:
In [30]:
A[e,:]
Out[30]:
In [31]:
detA = vol(A(e[1]),A(e[2]),A(e[3]));
detA.display()
Out[31]:

Of course, in general the determinant depends on the point $p \in \mathbb{U}$.

In [32]:
B = U.automorphism_field('B',latex_name=r'B');
B[e,:] = [[x,0,0],[0,y,0],[0,0,exp(z)]];
B.display()
Out[32]:
In [33]:
B.display_comp()
Out[33]:
In [34]:
B[e,:]
Out[34]:
In [35]:
detB = vol(B(e[1]),B(e[2]),B(e[3]));
detB.display()
Out[35]:
In [36]:
p = U.point((1,1,1),chart=coord);
detB(p)
Out[36]:
In [37]:
q = U.point((-1,1,0),chart=coord);
detB(q)
Out[37]:

Finally, we discuss how to code the results of Exercise 1.6.9 in O'Neill's Elementary Differential Geometry book. For this we need a metric (think: Riesz Representation Theorem). We'll use the Euclidean metric, a.k.a. the dot product.

In [38]:
g = U.riemannian_metric('g',latex_name=r'g');
g[1,1] = g[2,2] = g[3,3] =1;
print(g)
g.display()
Riemannian metric g on the 3-dimensional differentiable manifold U
Out[38]:
In [39]:
g.display_comp()
Out[39]:

The gradient of a function $f$ is the vector field dual to the differential $df$. Changing a covector field to a vector field is known as raising the indices, so the $\texttt{Sage}$ command is $\texttt{.up()}$.

In [40]:
gradf = df.up(g);
gradf.display()
Out[40]:
In [41]:
gradf.display_comp()
Out[41]:
In [42]:
df.display_comp()
Out[42]:

The curl of a vector field $X$ is the exterior derivative of the 1-form dual to $X$.

In [43]:
phi_X1 = X1.down(g);

To save key strokes, we can import a shortcut for $\texttt{.exterior_derivative()}$.

In [44]:
from sage.manifolds.utilities import xder
In [45]:
d_phi_X1 = xder(phi_X1);
print(d_phi_X1)
d_phi_X1.display()
2-form on the 3-dimensional differentiable manifold U
Out[45]:
In [46]:
d_phi_X1 == phi_X1.exterior_derivative()
Out[46]:

In terms of the basis of $\mathfrak{X}$, the curl of $X_1$ is:

In [47]:
d_phi_X1_dual= d_phi_X1.up(g);
d_phi_X1_dual.display()
Out[47]:
In [48]:
curl_X1 = U.vector_field(latex_name=r'\mathrm{curl}(X_1)');
curl_X1[:] = [0,0,d_phi_X1[1,2]];
curl_X1.display()
Out[48]:

Recall $X_1$ and verify that this corresponds with the result you'd obtain from Calc III.

In [49]:
X1.display()
Out[49]:

Finally, the divergence of a vector field $X$ is the coefficient of the $3$-form $d(\eta_X) = (\mathrm{div} X)\, dx \wedge dy \wedge dz$. Here, $\eta_X$ is the $2$-form corresponding to $X$ as described in O'Neill's exercise.

In [50]:
eta_X1 = U.diff_form(2,latex_name=r'\eta_{X_1}');
eta_X1[1,2] = X1[3];
eta_X1[1,3] = -X1[2];
eta_X1[2,3] = X1[1];
eta_X1.display()
Out[50]:
In [51]:
d_eta_X1 = xder(eta_X1);
d_eta_X1.display()
Out[51]:
In [52]:
div_X1 = d_eta_X1[1,2,3];
div_X1.display()
Out[52]:
In [53]:
eta_X2 = U.diff_form(2,latex_name=r'\eta_{X_2}');
eta_X2[1,2] = X2[3];
eta_X2[1,3] = -X2[2];
eta_X2[2,3] = X2[1];
eta_X2.display()
Out[53]:
In [54]:
d_eta_X2 = xder(eta_X2);
d_eta_X2.display()
Out[54]:
In [55]:
div_X2 = d_eta_X2[1,2,3];
div_X2.display()
Out[55]:

The Laplacian of a function $f \in \mathfrak{F}$ is $\Delta f = \mathrm{div}(\mathrm{grad}\, f)$.

In [56]:
eta_f = U.diff_form(2,latex_name=r'\eta_{f}');
eta_f[1,2] = gradf[3];
eta_f[1,3] = -gradf[2];
eta_f[2,3] = gradf[1];
eta_f.display()
Out[56]:
In [57]:
Laplacian_f = xder(eta_f)[1,2,3];
In [58]:
Laplacian_f.display()
Out[58]:
In [ ]: