Skip to content
The Lumenary

Math laboratory

Stokes's theorem and the periods of closed forms

Checks Stokes's theorem for x^3 dy on the unit disc by quadrature (both sides approximate 3*pi/4), then computes periods of the closed form dtheta round circles, an ellipse and a double loop in the punctured plane, and of a combination of two angle forms in the twice-punctured plane. Numerical evidence, with the quadrature error reported.

Back to the labNumerical approximation
Stokes's theorem and the periods of closed formsPythonNumerical approximationComputationally tested
"""Stokes's theorem on a disc, and periods of closed 1-forms.

Part 1 checks Stokes's theorem numerically for the 1-form x^3 dy on the unit
disc: the line integral round the circle and the area integral of
d(x^3 dy) = 3x^2 dx^dy both approximate 3*pi/4.

Part 2 integrates the closed form dtheta = (x dy - y dx)/(x^2 + y^2) on the
punctured plane round several loops. Its periods are 2*pi times winding
numbers, never anything else, and round a loop that misses the puncture the
period is 0, as Stokes predicts. With two punctures, a closed form is
determined up to exact forms by its two periods: H^1 of the twice-punctured
plane is R^2. All integrals are computed by quadrature (numerical evidence).
"""

import math

def line_integral(form, curve, n=4000):
    """Integral of the 1-form P dx + Q dy along a closed curve on [0, 2*pi].

    ``form(x, y)`` returns (P, Q); ``curve(t)`` returns (x, y, dx/dt, dy/dt).
    The trapezoid rule on a periodic integrand is very accurate.
    """
    h = 2 * math.pi / n
    total = 0.0
    for k in range(n):
        x, y, dx, dy = curve(k * h)
        p, q = form(x, y)
        total += p * dx + q * dy
    return total * h

def disc_integral(density, n_r=400, n_t=400):
    """Integral of a function over the unit disc, midpoint rule in polar form."""
    hr, ht = 1.0 / n_r, 2 * math.pi / n_t
    total = 0.0
    for i in range(n_r):
        r = (i + 0.5) * hr
        for j in range(n_t):
            t = (j + 0.5) * ht
            total += density(r * math.cos(t), r * math.sin(t)) * r
    return total * hr * ht

def angle_form(a=0.0, b=0.0):
    """dtheta measured from the point (a, b): ((x-a) dy - (y-b) dx) / r^2."""
    def form(x, y):
        dx, dy = x - a, y - b
        r2 = dx * dx + dy * dy
        return (-dy / r2, dx / r2)
    return form

def circle(cx, cy, radius, turns=1):
    """A circle traversed ``turns`` times anticlockwise, as (x, y, x', y')."""
    def curve(t):
        s = turns * t
        return (cx + radius * math.cos(s), cy + radius * math.sin(s),
                -radius * turns * math.sin(s), radius * turns * math.cos(s))
    return curve

def ellipse(a, b):
    """The ellipse (a cos t, b sin t), anticlockwise."""
    return lambda t: (a * math.cos(t), b * math.sin(t),
                      -a * math.sin(t), b * math.cos(t))

def combine(c1, f1, c2, f2):
    """The 1-form c1 f1 + c2 f2."""
    def form(x, y):
        p1, q1 = f1(x, y)
        p2, q2 = f2(x, y)
        return (c1 * p1 + c2 * p2, c1 * q1 + c2 * q2)
    return form

def main():
    exact = 3 * math.pi / 4
    lhs = line_integral(lambda x, y: (0.0, x**3), circle(0, 0, 1))
    rhs = disc_integral(lambda x, y: 3 * x * x)
    print("1. Stokes for w = x^3 dy on the unit disc (exact value 3*pi/4):")
    print(f"   boundary integral  {lhs:.10f}   error {abs(lhs - exact):.1e}")
    print(f"   integral of dw     {rhs:.10f}   error {abs(rhs - exact):.1e}")
    print()
    print("2. Periods of dtheta = (x dy - y dx)/(x^2 + y^2), divided by 2*pi:")
    loops = [
        ("unit circle round 0", circle(0, 0, 1)),
        ("circle of radius 0.01 round 0", circle(0, 0, 0.01)),
        ("ellipse 3 x 0.2 round 0", ellipse(3, 0.2)),
        ("circle round 0, twice", circle(0, 0, 1, turns=2)),
        ("circle centred at (3, 0)", circle(3, 0, 1)),
    ]
    for name, loop in loops:
        ratio = round(line_integral(angle_form(), loop) / (2 * math.pi), 8)
        print(f"   {name:<32} {ratio + 0.0:+.8f}")
    print("   Annulus 0.01 < r < 1: outer minus inner period = 0 = integral of")
    print("   d(dtheta), so Stokes holds although dtheta is not exact.")
    print()
    form = combine(2.0, angle_form(-1, 0), -0.5, angle_form(1, 0))
    print("3. Two punctures at (-1, 0) and (1, 0); w = 2 dth_left - 0.5 dth_right:")
    for name, loop in [("loop round (-1, 0)", circle(-1, 0, 0.5)),
                       ("loop round (1, 0)", circle(1, 0, 0.5)),
                       ("loop round both", circle(0, 0, 3))]:
        print(f"   {name:<20} period / 2*pi = "
              f"{line_integral(form, loop) / (2 * math.pi):+.6f}")
    print("   The two periods (2, -0.5) pin down the class of w: H^1 = R^2.")
    print()
    print("Epistemic status: numerical quadrature. The agreement in part 1 is")
    print("evidence for one form on one disc; the integer periods in part 2 are")
    print("evidence for the theorem that periods of dtheta are 2*pi times winding")
    print("numbers. The proofs are Stokes's theorem and the lesson's argument.")

if __name__ == "__main__":
    main()
Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.

Used in