Wichita State University, Dept. of Mathematics
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
So future readers know what version we're using:
version()
Force $\LaTeX$ display:
%display latex
Define the chart we're working in/on:
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}$.
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.
t1w2 = t1.wedge(t2);
print(t1w2)
t1w2.display()
Exterior products are alternating.
t2w1 = t2.wedge(t1);
t2w1 == -t1w2
The exterior derivative of a form increases the degree by 1.
dt1 = t1.exterior_derivative();
dt2 = t2.exterior_derivative();
print(dt1)
dt1.display()
print(dt2)
dt2.display()
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.
f = U.scalar_field({coord: x^2 - 2*z^(sin(y))});
df = f.exterior_derivative();
print(df)
df.display()
df == f.differential()
Applying the exterior derivative to the same form twice always yields 0 (i.e., the form identically equal to 0).
ddf = df.exterior_derivative();
print(ddf)
ddf.display()
ddt1 = dt1.exterior_derivative();
print(ddt1)
ddt1.display()
ddt2 = dt2.exterior_derivative();
print(ddt2)
ddt2.display()
Differential $k$-forms map $\mathfrak{X}^k \to \mathfrak{F}$.
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];
print(df(X1))
df(X1).display()
$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$.
print(X1(f))
X1(f).display()
df(X1) == X1(f)
$2$-forms take two vector fields as arguments.
dt1(X1,X2).display()
dt1(X2,X1).display()
dt1(X1,X2) == -dt1(X2,X1)
The space $\Omega^n$ is a 1-dimensional space whose basis covector is the Euclidean volume form on $\mathbb{U}$.
vol = U.diff_form(3,latex_name=r'\omega');
vol[1,2,3] = 1;
print(vol)
vol.display()
vol(2*e[1],4*e[2],e[3])
vol(2*e[1],4*e[2],e[3]).display()
p=U.point((1,2,3))
vol(2*e[1],4*e[2],e[3])(p)
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}$.
A = U.automorphism_field('aut',latex_name=r'A');
A[e,:] = [[1,x,z],[0,3,y],[0,0,5]];
print(A)
A.display()
A.display_comp()
A[e,:]
detA = vol(A(e[1]),A(e[2]),A(e[3]));
detA.display()
Of course, in general the determinant depends on the point $p \in \mathbb{U}$.
B = U.automorphism_field('B',latex_name=r'B');
B[e,:] = [[x,0,0],[0,y,0],[0,0,exp(z)]];
B.display()
B.display_comp()
B[e,:]
detB = vol(B(e[1]),B(e[2]),B(e[3]));
detB.display()
p = U.point((1,1,1),chart=coord);
detB(p)
q = U.point((-1,1,0),chart=coord);
detB(q)
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.
g = U.riemannian_metric('g',latex_name=r'g');
g[1,1] = g[2,2] = g[3,3] =1;
print(g)
g.display()
g.display_comp()
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()}$.
gradf = df.up(g);
gradf.display()
gradf.display_comp()
df.display_comp()
The curl of a vector field $X$ is the exterior derivative of the 1-form dual to $X$.
phi_X1 = X1.down(g);
To save key strokes, we can import a shortcut for $\texttt{.exterior_derivative()}$.
from sage.manifolds.utilities import xder
d_phi_X1 = xder(phi_X1);
print(d_phi_X1)
d_phi_X1.display()
d_phi_X1 == phi_X1.exterior_derivative()
In terms of the basis of $\mathfrak{X}$, the curl of $X_1$ is:
d_phi_X1_dual= d_phi_X1.up(g);
d_phi_X1_dual.display()
curl_X1 = U.vector_field(latex_name=r'\mathrm{curl}(X_1)');
curl_X1[:] = [0,0,d_phi_X1[1,2]];
curl_X1.display()
Recall $X_1$ and verify that this corresponds with the result you'd obtain from Calc III.
X1.display()
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.
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()
d_eta_X1 = xder(eta_X1);
d_eta_X1.display()
div_X1 = d_eta_X1[1,2,3];
div_X1.display()
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()
d_eta_X2 = xder(eta_X2);
d_eta_X2.display()
div_X2 = d_eta_X2[1,2,3];
div_X2.display()
The Laplacian of a function $f \in \mathfrak{F}$ is $\Delta f = \mathrm{div}(\mathrm{grad}\, f)$.
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()
Laplacian_f = xder(eta_f)[1,2,3];
Laplacian_f.display()