Skip to content
The Lumenary

Math laboratory

Green's theorem: circulation versus integrated curl

Computes the circulation of a planar vector field around circles (by the trapezoid rule in the angle) and the double integral of its curl over the discs (midpoint rule in polar coordinates). For a smooth field both are 3 pi / 2; for the vortex field around the origin they are 2 pi and 0, showing why Green's theorem needs F to be C^1 on the whole disc.

Back to the labNumerical approximationCounterexample
Green's theorem: circulation versus integrated curlPythonNumerical approximationCounterexampleComputationally tested
"""Green's theorem, numerically: circulation around a circle versus curl inside.

Green's theorem says the circulation of a C^1 field F = (P, Q) around the
boundary of a region D equals the double integral of curl F = Q_x - P_y over
D. We compute both sides numerically for circles. For the smooth field
(-y^3, x^3) they agree. For the vortex (-y, x)/(x^2 + y^2) they disagree on a
circle around the origin (2 pi versus 0): the field is singular at the
origin, so the hypothesis "C^1 on all of D" fails - and the circulation
measures the hole.

Runs unchanged in the browser (Pyodide) using only the standard library.
"""

import math

def circulation(P, Q, centre, radius, n=2000):
    """Approximate the circulation of (P, Q) counterclockwise around a circle.

    Uses the trapezoid rule in the angle t, which is very accurate for smooth
    periodic integrands.
    """
    cx, cy = centre
    total = 0.0
    for i in range(n):
        t = 2 * math.pi * i / n
        x, y = cx + radius * math.cos(t), cy + radius * math.sin(t)
        dx, dy = -radius * math.sin(t), radius * math.cos(t)
        total += P(x, y) * dx + Q(x, y) * dy
    return total * 2 * math.pi / n

def disc_integral(g, centre, radius, n_r=200, n_t=200):
    """Approximate the integral of g over a disc, in polar coordinates.

    Midpoint rule in r and t; the factor r is the Jacobian of polar coordinates.
    """
    cx, cy = centre
    hr, ht = radius / 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 += g(cx + r * math.cos(t), cy + r * math.sin(t)) * r
    return total * hr * ht

def smooth_P(x, y):
    """First component of the smooth field (-y^3, x^3)."""
    return -y**3

def smooth_Q(x, y):
    """Second component of the smooth field (-y^3, x^3)."""
    return x**3

def smooth_curl(x, y):
    """curl (-y^3, x^3) = Q_x - P_y = 3x^2 + 3y^2."""
    return 3 * x**2 + 3 * y**2

def vortex_P(x, y):
    """First component of the vortex field -y / (x^2 + y^2)."""
    return -y / (x**2 + y**2)

def vortex_Q(x, y):
    """Second component of the vortex field x / (x^2 + y^2)."""
    return x / (x**2 + y**2)

def vortex_curl(x, y):
    """curl of the vortex field, which is 0 wherever it is defined."""
    return 0.0

def main():
    rows = [
        ("(-y^3, x^3)", smooth_P, smooth_Q, smooth_curl, (0, 0), 1),
        ("(-y^3, x^3)", smooth_P, smooth_Q, smooth_curl, (1, 0.5), 0.8),
        ("vortex", vortex_P, vortex_Q, vortex_curl, (0, 0), 1),
        ("vortex", vortex_P, vortex_Q, vortex_curl, (0, 0), 0.01),
        ("vortex", vortex_P, vortex_Q, vortex_curl, (2, 0), 1),
    ]
    print("Circulation around a circle versus the integral of curl inside")
    print("field         centre       radius   circulation   integral of curl")
    for name, P, Q, curl, c, r in rows:
        circ = circulation(P, Q, c, r)
        inner = disc_integral(curl, c, r)
        centre = f"({c[0]}, {c[1]})"
        print(f"{name:<13} {centre:<12} {r:<7}  {circ:11.6f}   {inner:11.6f}")
    print(f"For reference: 3 pi / 2 = {1.5 * math.pi:.6f}, 2 pi = {2 * math.pi:.6f}")
    print("Smooth field: the two columns agree, as Green's theorem says.")
    print("Vortex around the origin: circulation 2 pi on every circle, however")
    print("small, but curl 0 wherever the field is defined. Around (2, 0), away")
    print("from the singularity, both sides are 0.")
    print()
    print("Epistemic status: numerical quadrature (trapezoid and midpoint rules),")
    print("accurate here to many digits but not a proof. That the circulation of")
    print("the vortex around the unit circle is exactly 2 pi is a short exact")
    print("computation (formalised in the lesson's Lean file); Green's theorem")
    print("itself is proved in the lesson for rectangles.")

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

Used in