From 72a8b0621eedd66709c9f09f99d9c1a80e134d6d Mon Sep 17 00:00:00 2001 From: ARS183 <1028762817@qq.com> Date: Thu, 27 Aug 2026 13:10:13 +0200 Subject: [PATCH 01/17] Add Week 1 computer lab on gradient and divergence --- .../labs/fwtools.py | 228 ++++++ .../labs/week01-grad-div.md | 704 ++++++++++++++++++ book/_toc.yml | 1 + 3 files changed, 933 insertions(+) create mode 100644 book/1_gradient_divergence_curl/labs/fwtools.py create mode 100644 book/1_gradient_divergence_curl/labs/week01-grad-div.md diff --git a/book/1_gradient_divergence_curl/labs/fwtools.py b/book/1_gradient_divergence_curl/labs/fwtools.py new file mode 100644 index 0000000..02bb4dc --- /dev/null +++ b/book/1_gradient_divergence_curl/labs/fwtools.py @@ -0,0 +1,228 @@ +"""Plotting and self-check helpers for the ECTB2140 *Fields and Waves* labs. + +You are **not** expected to read or edit this file during a lab session. It +exists so that your time goes on the physics -- writing fields, gradients and +divergences -- rather than on plotting boilerplate. + +Everything here works on a 3-D Cartesian grid built with ``indexing='ij'``, +which means the array axes are (x, y, z) in that order. That choice matters: +it makes ``np.gradient(F, dx, dy, dz)`` return the derivatives in the same +order as the coordinates, with no index gymnastics. + +Requires: numpy, matplotlib, plotly. +""" + +from __future__ import annotations + +import numpy as np +import matplotlib.pyplot as plt +import plotly.graph_objects as go + +__all__ = [ + "make_grid_3d", "z0_index", "slice_z0", + "show_isosurfaces", "show_cones", "show_scalar_slice", "show_field_slice", + "check", "check_shape", "check_close", +] + +# -------------------------------------------------------------------------- +# Grid +# -------------------------------------------------------------------------- + +def make_grid_3d(n: int = 61, L: float = 2.0): + """A cube of sample points on [-L, L]^3 with n points per side. + + Returns + ------- + X, Y, Z : (n, n, n) float arrays + Coordinates, built with indexing='ij' so that X[i, j, k] = x[i], + Y[i, j, k] = y[j] and Z[i, j, k] = z[k]. + dx, dy, dz : float + Uniform spacings. np.gradient needs these -- omit them and it assumes + a spacing of 1, making every derivative wrong by a constant factor. + """ + if n % 2 == 0: + raise ValueError("use an odd n so that the grid contains the origin exactly") + a = np.linspace(-L, L, n) + X, Y, Z = np.meshgrid(a, a, a, indexing="ij") + h = a[1] - a[0] + return X, Y, Z, h, h, h + + +def z0_index(Z: np.ndarray) -> int: + """Index k of the z = 0 plane in an indexing='ij' grid.""" + return int(np.argmin(np.abs(Z[0, 0, :]))) + + +def slice_z0(F: np.ndarray, Z: np.ndarray) -> np.ndarray: + """The z = 0 plane of a scalar field, as a 2-D (x, y) array.""" + return F[:, :, z0_index(Z)] + + +# -------------------------------------------------------------------------- +# 3-D views (plotly) +# -------------------------------------------------------------------------- + +def show_isosurfaces(X, Y, Z, F, levels, *, title="", opacity=0.35, + colorscale="Viridis", show_caps=False, size=620, step=2): + """Draw one or more isosurfaces (level sets) of a scalar field F. + + An isosurface is the set of points where F takes one fixed value -- the + 3-D analogue of a contour line. Transparency lets you see the inner + surfaces through the outer ones, so pass a list of levels and look at the + nesting. + """ + levels = np.atleast_1d(np.asarray(levels, dtype=float)) + # Subsample before handing the volume to plotly. A full 61^3 grid embeds + # ~12 MB of JSON per figure; every other point looks identical on screen. + sl = (slice(None, None, step),) * 3 + X, Y, Z, F = X[sl], Y[sl], Z[sl], np.asarray(F)[sl] + fig = go.Figure( + go.Isosurface( + x=X.ravel(), y=Y.ravel(), z=Z.ravel(), value=np.asarray(F).ravel(), + isomin=float(levels.min()), isomax=float(levels.max()), + surface_count=int(levels.size), opacity=opacity, + colorscale=colorscale, showscale=True, + caps=dict(x_show=show_caps, y_show=show_caps, z_show=show_caps), + ) + ) + _style_3d(fig, title, size) + return fig + + +def show_cones(X, Y, Z, Ax, Ay, Az, *, step=8, title="", sizeref=0.6, + colorscale="Blues", size=620, normalise=False): + """Draw a 3-D vector field as a lattice of cones (arrows). + + Only every ``step``-th sample in each direction is drawn -- a full grid of + cones is an unreadable haystack. Set ``normalise=True`` to show direction + only, with every cone the same length; this is often clearer for fields + whose magnitude varies over orders of magnitude. + """ + sl = (slice(None, None, step),) * 3 + x, y, z = X[sl].ravel(), Y[sl].ravel(), Z[sl].ravel() + u, v, w = np.asarray(Ax)[sl].ravel(), np.asarray(Ay)[sl].ravel(), np.asarray(Az)[sl].ravel() + + finite = np.isfinite(u) & np.isfinite(v) & np.isfinite(w) + x, y, z, u, v, w = (a[finite] for a in (x, y, z, u, v, w)) + + if normalise: + mag = np.sqrt(u**2 + v**2 + w**2) + mag[mag == 0] = 1.0 + u, v, w = u / mag, v / mag, w / mag + + fig = go.Figure( + go.Cone(x=x, y=y, z=z, u=u, v=v, w=w, + sizemode="scaled", sizeref=sizeref, anchor="tail", + colorscale=colorscale, showscale=True, + colorbar=dict(title="|A|")), + ) + _style_3d(fig, title, size) + return fig + + +def _style_3d(fig, title, size): + fig.update_layout( + title=title, width=size, height=size, + margin=dict(l=0, r=0, t=40 if title else 0, b=0), + scene=dict( + xaxis_title="x [m]", yaxis_title="y [m]", zaxis_title="z [m]", + aspectmode="cube", # equal aspect: never distort a field + camera=dict(eye=dict(x=1.6, y=1.6, z=1.1)), + ), + ) + + +# -------------------------------------------------------------------------- +# 2-D views of the z = 0 plane (matplotlib) +# -------------------------------------------------------------------------- + +def show_scalar_slice(X, Y, Z, F, *, title="", label="", cmap="RdYlBu_r", + levels=25, symmetric=False, percentile=99, ax=None): + """Filled contours of a scalar field in the z = 0 plane.""" + k = z0_index(Z) + x2, y2, f2 = X[:, :, k], Y[:, :, k], np.asarray(F)[:, :, k] + + hi = np.nanpercentile(np.abs(f2) if symmetric else f2, percentile) + lo = -hi if symmetric else np.nanpercentile(f2, 100 - percentile) + lv = np.linspace(lo, hi, levels) + + created = ax is None + if created: + _, ax = plt.subplots(figsize=(5.4, 4.5)) + cf = ax.contourf(x2, y2, np.clip(f2, lo, hi), levels=lv, cmap=cmap, extend="both") + ax.set_aspect("equal") # course rule: never distort a field plot + ax.set_xlabel("$x$ [m]") + ax.set_ylabel("$y$ [m]") + ax.set_title(title) + if created: + ax.figure.colorbar(cf, ax=ax, label=label) + return ax, cf + + +def show_field_slice(X, Y, Z, Ax, Ay, *, background=None, title="", label="", + cmap="RdBu_r", density=1.3, symmetric=True, ax=None, + percentile=98): + """Streamlines of a vector field in the z = 0 plane, over an optional + scalar background (typically the potential that generated it).""" + k = z0_index(Z) + created = ax is None + if created: + _, ax = plt.subplots(figsize=(5.8, 4.8)) + + cf = None + if background is not None: + _, cf = show_scalar_slice(X, Y, Z, background, cmap=cmap, symmetric=symmetric, + percentile=percentile, ax=ax) + + # streamplot needs 1-D increasing axes and arrays shaped (ny, nx); our + # indexing='ij' arrays are (nx, ny), hence the transposes. + x1 = X[:, 0, k] + y1 = Y[0, :, k] + u = np.nan_to_num(np.asarray(Ax)[:, :, k]).T + v = np.nan_to_num(np.asarray(Ay)[:, :, k]).T + ax.streamplot(x1, y1, u, v, color="k", linewidth=0.7, + density=density, arrowsize=0.9) + + ax.set_aspect("equal") + ax.set_xlim(x1.min(), x1.max()) + ax.set_ylim(y1.min(), y1.max()) + ax.set_xlabel("$x$ [m]") + ax.set_ylabel("$y$ [m]") + ax.set_title(title) + if created and cf is not None: + ax.figure.colorbar(cf, ax=ax, label=label) + return ax + + +# -------------------------------------------------------------------------- +# Self-checks +# -------------------------------------------------------------------------- + +def check(label: str, ok: bool, hint: str = "") -> None: + """Report a pass, or raise with a hint about what to look at.""" + if ok: + print(f" [ok] {label}") + else: + raise AssertionError(f"{label} -- {hint}" if hint else label) + + +def check_shape(label: str, arr, expected) -> None: + arr = np.asarray(arr) + check(f"{label}: shape {arr.shape}", arr.shape == tuple(expected), + f"expected {tuple(expected)}, got {arr.shape}. Did every array come " + f"from the same grid?") + + +def check_close(label: str, got, want, rtol=0.05, where=None) -> None: + """Compare two arrays where both are finite (and where `where` is True).""" + got, want = np.asarray(got, float), np.broadcast_to(np.asarray(want, float), np.shape(got)) + m = np.isfinite(got) & np.isfinite(want) + if where is not None: + m = m & where + if not m.any(): + raise AssertionError(f"{label} -- nothing left to compare; the mask removed every point") + rel = np.abs(got[m] - want[m]) / np.maximum(np.abs(want[m]), 1e-30) + worst = float(np.max(rel)) + check(f"{label}: worst error {worst:.2%}", worst < rtol, + f"worst relative error {worst:.2%} exceeds {rtol:.0%}. Check your " + f"np.gradient call -- did you pass dx, dy, dz, and in that order?") diff --git a/book/1_gradient_divergence_curl/labs/week01-grad-div.md b/book/1_gradient_divergence_curl/labs/week01-grad-div.md new file mode 100644 index 0000000..5dc7974 --- /dev/null +++ b/book/1_gradient_divergence_curl/labs/week01-grad-div.md @@ -0,0 +1,704 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +mystnb: + # This page is a workbook: its task cells contain `___` blanks that raise + # NameError by design, and every later cell depends on variables those tasks + # define. Executing it at build time would fail the build, so it is switched + # off for this page alone -- the book-wide setting is untouched. Readers run + # the code themselves with Live Code. + execution_mode: 'off' +--- + +# Gradient and Divergence + +:::{admonition} Computer lab +:class: note + +A practical companion to the lecture notes on the gradient and the divergence. Here you build both operators yourself, in three dimensions, and look at what they do. +::: + +## How this lab works + +**You write the code.** Not one line at a time into someone else's function — you write the fields, the operators and the checks. Each task states a physical question, gives you the steps, and ends with a self-check you can run. + +What we supply is the *plotting*, in a module called `fwtools`. Drawing a transparent isosurface in plotly is fiddly and teaches you nothing about electromagnetism, so that part is done for you. Your time goes on physics. + +**Nine tasks, about ten minutes each.** After each one there is a dropdown solution. Open it *after* you have tried, or when you are stuck for more than a couple of minutes — being stuck on syntax is not the point of this lab. + +**A running theme.** Watch for the moment in Part 2 where a single minus sign turns a piece of geometry into a piece of physics. + +--- + +## Part 0 — Setup + +Run these two cells. The first imports what we need; the second builds the cube of sample points that everything else lives on. + +```{code-cell} ipython3 +import sys, pathlib + +import numpy as np +import matplotlib.pyplot as plt +from scipy.constants import epsilon_0 + +# Live Code runs Python in your browser, on Pyodide. Pyodide bundles numpy, +# scipy and matplotlib, but not plotly -- so fetch it when it is missing. +# Running locally, plotly is already installed and this branch never executes. +try: + import plotly.io as pio +except ModuleNotFoundError: + print("Fetching plotly. A few seconds, and only the first time...") + import micropip + await micropip.install("plotly") + import plotly.io as pio + +# plotly refuses to display a figure unless it can find nbformat >= 4.2, which +# it uses only to decide that it is running inside a notebook. Pyodide has no +# nbformat, so give it one. +try: + import nbformat # noqa: F401 +except ModuleNotFoundError: + import micropip, types + try: + await micropip.install("nbformat") + except Exception: + # nbformat pulls in jsonschema, which may not be installable here. + # The version string is the only part plotly actually reads. + _nb = types.ModuleType("nbformat") + _nb.__version__ = "5.10.4" + sys.modules["nbformat"] = _nb + +# fwtools holds the plotting helpers. Where it sits depends on how you are +# running: your own folder in JupyterLab, or the browser's virtual filesystem +# under Live Code. Look in the likely places rather than assume. +for _p in (".", "week-01-Grad-Div", "/week-01-Grad-Div", "book/week-01-Grad-Div"): + if (pathlib.Path(_p) / "fwtools.py").exists(): + sys.path.insert(0, _p) + break +try: + import fwtools as fw +except ModuleNotFoundError: + from pyodide.http import pyfetch # Live Code only + _r = await pyfetch("fwtools.py") # sits beside this page + pathlib.Path("fwtools.py").write_bytes(await _r.bytes()) + import fwtools as fw + +pio.renderers.default = "plotly_mimetype+notebook" + +K = 1.0 / (4.0 * np.pi * epsilon_0) # the Coulomb constant, 8.99e9 V*m/C +Q = 1e-9 # 1 nC, a convenient test charge + +print(f"epsilon_0 = {epsilon_0:.4e} F/m") +print(f"K = {K:.4e} V*m/C") +``` + +```{code-cell} ipython3 +X, Y, Z, dx, dy, dz = fw.make_grid_3d(n=61, L=2.0) + +print(f"grid shape {X.shape}, spacing {dx:.4f} m, {X.size:,} sample points") +print(f"X[i,j,k] = x[i] -> X[-1, 0, 0] = {X[-1, 0, 0]:.1f} m") +``` + +:::{admonition} Why `indexing='ij'`, and why you should care +:class: tip + +`np.meshgrid` has two conventions. The default, `indexing='xy'`, puts **y on axis 0** — so `np.gradient` hands back the *y*-derivative first, and half of all numerical field bugs come from that one fact. + +We use `indexing='ij'` instead, so axis 0 is x, axis 1 is y, axis 2 is z: + +```python +dfdx, dfdy, dfdz = np.gradient(f, dx, dy, dz) # in the order you expect +``` + +Two rules that follow, and that you will use in every task today: + +1. **Always pass the spacings** `dx, dy, dz`. Leave them out and `np.gradient` assumes a spacing of 1, making every derivative wrong by a factor of 15. +2. **Derivatives come back in coordinate order.** No transposes, no surprises. +::: + +--- + +## Part 1 — The distance function, and what its gradient is + +Before any physics, one piece of pure geometry. The simplest scalar field there is: + +$$ r(x,y,z) = \sqrt{(x-x_0)^2 + (y-y_0)^2 + (z-z_0)^2} $$ + +*How far am I from that point?* One number at every location in space. No charge, no potential, no units of anything — just distance. + +### Task 1 — build the distance field + +```{code-cell} ipython3 +# Task 1 +# The distance from every grid point to a source at (x0, y0, z0) is +# r = sqrt( (x-x0)^2 + (y-y0)^2 + (z-z0)^2 ) +# Replace each ___ below. Note that X, Y, Z are whole arrays, so writing +# (X - x0)**2 squares every point at once -- no loops anywhere today. +# +# Write your code here: + +def distance_to(X, Y, Z, x0=0.0, y0=0.0, z0=0.0): + return np.sqrt(___ + ___ + ___) + + +r = distance_to(___, ___, ___) # source at the origin + +# --- self-check (leave this alone) --- +c = X.shape[0] // 2 # index of the origin +fw.check_shape("r", r, X.shape) +fw.check("r = 0 at the origin", np.isclose(r[c, c, c], 0.0)) +fw.check("r = 2 m at (2,0,0)", np.isclose(r[-1, c, c], 2.0)) +fw.check("r = 2 m at (0,2,0)", np.isclose(r[c, -1, c], 2.0)) +``` + +:::{admonition} Solution — Task 1 +:class: dropdown + +```python +# Task 1 solution +def distance_to(X, Y, Z, x0=0.0, y0=0.0, z0=0.0): + return np.sqrt((X - x0)**2 + (Y - y0)**2 + (Z - z0)**2) + + +r = distance_to(X, Y, Z) +``` +::: + +### What does this field look like? + +A surface on which $r$ takes one fixed value is called an **isosurface**, or level set — the three-dimensional version of a contour line on a map. Draw a few, with transparency, so you can see through the outer ones to the inner ones. + +```{code-cell} ipython3 +fw.show_isosurfaces(X, Y, Z, r, levels=[0.5, 1.0, 1.5], + title="Isosurfaces of the distance function r") +``` + +**Drag the figure to rotate it.** They are spheres, nested inside one another — which is only to say that "all the points 1 metre from here" *is* a sphere. Nothing deeper than that. But it is worth seeing, because in a moment the gradient is going to be perpendicular to these surfaces, and that will not be a coincidence. + +### Task 2 — the gradient of the distance + +Now compute $\nabla r$. Before you run it, predict two things and write them down: + +- **which way** do you expect the arrows to point? +- **how long** do you expect them to be? + +```{code-cell} ipython3 +# Task 2 +# np.gradient returns one array per axis. Because our grid uses +# indexing='ij', they arrive in the order (d/dx, d/dy, d/dz) -- and you must +# pass the three spacings, or every derivative is wrong by a factor of 15. +# +# Fill in the blanks, then look hard at the printed magnitudes. +# +# Write your code here: + +grx, gry, grz = np.gradient(___, ___, ___, ___) + +grad_r_mag = np.sqrt(___ + ___ + ___) + +for name, idx in [("(2,0,0)", (-1, c, c)), ("(0,2,0)", (c, -1, c))]: + print(f"|grad r| at {name} = {grad_r_mag[idx]:.4f}") + +# --- self-check (leave this alone) --- +band = (r > 0.4) & (r < 1.6) +fw.check_shape("grad r", grx, X.shape) +fw.check_close("|grad r| = 1 everywhere", grad_r_mag, 1.0, rtol=0.05, where=band) +``` + +:::{admonition} Solution — Task 2 +:class: dropdown + +```python +# Task 2 solution +grx, gry, grz = np.gradient(r, dx, dy, dz) +grad_r_mag = np.sqrt(grx**2 + gry**2 + grz**2) + +for (i, j, k), name in [((-1, c, c), "(2,0,0)"), ((c, -1, c), "(0,2,0)")]: + print(f"|grad r| at {name} = {grad_r_mag[i, j, k]:.4f}") +print(f"|grad r| median away from the origin = " + f"{np.median(grad_r_mag[(r > 0.4) & (r < 1.6)]):.4f}") +``` +::: + +:::{admonition} The magnitude is 1. Everywhere. +:class: important + +That is not a numerical accident, and it is worth a moment. + +Walk one metre directly away from the source point. Your distance from it increases by exactly one metre. The steepest possible rate of change of $r$ is therefore $1$ metre per metre — a slope of 1 — no matter where you are standing. + +So the gradient of the distance function is a **unit vector pointing radially outward**: + +$$ \nabla r = \hat{\mathbf{a}}_R $$ + +This is the cleanest possible illustration of what a gradient *is*: the direction of steepest increase, with a length equal to that rate of increase. Here the direction is "away from the source" and the rate is 1. +::: + +### Task 3 — see it + +```{code-cell} ipython3 +# Task 3 +# Draw the gradient field. Fill in the three components, then rotate the +# figure and compare it with the isosurfaces above: every arrow should +# pierce the spheres at a right angle. +# +# Write your code here: + +fw.show_cones(X, Y, Z, ___, ___, ___, step=8, + title="grad r -- unit vectors pointing away from the source") +``` + +:::{admonition} Solution — Task 3 +:class: dropdown + +```python +# Task 3 solution +fw.show_cones(X, Y, Z, grx, gry, grz, step=8, + title="grad r -- unit vectors pointing away from the source") +``` + +The arrows are perpendicular to the spheres because moving *along* a sphere does not change $r$ at all. If a direction produces no change, the gradient has no component along it — so the gradient must be entirely perpendicular to the level surface. That argument works for every scalar field, not just this one. +::: + +--- + +## Part 2 — Invert it, and watch the arrows turn round + +Now the function the physics actually uses: not the distance, but **one over** the distance. + +$$ f(r) = \frac{1}{r} $$ + +Same spheres as isosurfaces — $f$ is constant wherever $r$ is constant. But the *ordering* has been turned inside out: $f$ is now largest near the source and decays to nothing far away. + +### Task 4 — the gradient of the inverse distance + +```{code-cell} ipython3 +# Task 4 +# Now the same two steps for f = 1/r. The masking line is given, because +# dividing by zero at the origin is a detail rather than a lesson. The rest +# is yours -- it is the same shape as Task 2. +# +# 1. Take the gradient of f. Call the components fx, fy, fz. +# 2. Build its magnitude, f_mag. +# 3. Print f_mag against 1/r^2 at r = 0.6, 1.0 and 1.5 m. +# 4. Predict the DIRECTION first, then draw it: +# fw.show_cones(X, Y, Z, fx, fy, fz, step=8, normalise=True, title=...) +# +# Write your code here: + +r_masked = np.where(r < 0.25, np.nan, r) +f = 1.0 / r_masked + + + +# --- self-check (leave this alone) --- +interior = np.zeros_like(r, dtype=bool) +interior[2:-2, 2:-2, 2:-2] = True # np.gradient is less accurate at the edges +outside = (r > 0.5) & interior +fw.check_close("|grad(1/r)| = 1/r^2", f_mag, 1.0 / r_masked**2, rtol=0.05, where=outside) +fw.check("grad(1/r) points inward at (1,0,0)", fx[-1 - 15, c, c] < 0) +``` + +:::{admonition} Solution — Task 4 +:class: dropdown + +```python +# Task 4 solution +r_masked = np.where(r < 0.25, np.nan, r) +f = 1.0 / r_masked + +fx, fy, fz = np.gradient(f, dx, dy, dz) +f_mag = np.sqrt(fx**2 + fy**2 + fz**2) + +for rr in (0.6, 1.0, 1.5): + i = int(np.argmin(np.abs(X[:, 0, 0] - rr))) + print(f"r = {rr:.1f} m : |grad f| = {f_mag[i, c, c]:8.4f} 1/r^2 = {1/rr**2:8.4f}") + +fw.show_cones(X, Y, Z, fx, fy, fz, step=8, normalise=True, + title="grad(1/r) -- pointing back towards the source") +``` +::: + +:::{admonition} The gradient points towards *increase* — always +:class: important + +The arrows have reversed. Same spheres, same source, opposite direction: + +$$ \nabla r = +\hat{\mathbf{a}}_R, \qquad\qquad \nabla\!\left(\frac{1}{r}\right) = -\frac{1}{r^{2}}\,\hat{\mathbf{a}}_R $$ + +Nothing about space changed. What changed is **which way the function climbs**. $r$ grows as you move away, so $\nabla r$ points away. $1/r$ grows as you move *closer*, so $\nabla(1/r)$ points inward — steeply, as $1/r^2$, because $1/r$ climbs ever faster near the source. + +A gradient always points along the direction of maximum increase of its own function. It knows nothing about sources, sinks, charges or fields; it only knows uphill. +::: + +### Task 5 — from geometry to physics + +Here is where the physics enters, and it enters as a single minus sign. + +The electric potential of a point charge $q$ is the inverse-distance function with a constant in front: + +$$ V(r) = \frac{1}{4\pi\varepsilon_0}\frac{q}{r} $$ + +and the electric field is defined as + +$$ \mathbf{E} = -\nabla V $$ + +You already know what $\nabla V$ does: it points *inward*, uphill towards the charge. The minus sign turns it round. **The field points downhill** — which is exactly what a positive test charge released from rest would do, running away from a positive source and losing potential energy as it goes. + +```{code-cell} ipython3 +# Task 5 +# The potential is given. Everything after it is yours. +# +# 1. Get E = -grad V. Call the components Ex, Ey, Ez. +# 2. Build E_mag, and compare it against the analytic K*Q/r^2 at a few radii. +# 3. Draw it with normalise=True and confirm it points OUTWARD for q > 0. +# +# Write your code here: + +V = K * Q / r_masked + + + +# --- self-check (leave this alone) --- +fw.check_close("|E| = q/(4 pi eps0 r^2)", E_mag, K * Q / r_masked**2, + rtol=0.05, where=outside) +fw.check("E points outward at (1,0,0)", Ex[-1 - 15, c, c] > 0) +``` + +:::{admonition} Solution — Task 5 +:class: dropdown + +```python +# Task 5 solution +V = K * Q / r_masked + +dVdx, dVdy, dVdz = np.gradient(V, dx, dy, dz) +Ex, Ey, Ez = -dVdx, -dVdy, -dVdz +E_mag = np.sqrt(Ex**2 + Ey**2 + Ez**2) + +for rr in (0.6, 1.0, 1.5): + i = int(np.argmin(np.abs(X[:, 0, 0] - rr))) + print(f"r = {rr:.1f} m : |E| = {E_mag[i, c, c]:8.3f} V/m " + f"analytic = {K*Q/rr**2:8.3f} V/m") + +fw.show_cones(X, Y, Z, Ex, Ey, Ez, step=8, normalise=True, + title="E = -grad V for a positive point charge") +``` +::: + +--- + +## Part 3 — Two sources: a source and a sink + +One charge is symmetric enough to be boring. Put down two. + +$$ V_{\text{total}} = \frac{1}{4\pi\varepsilon_0}\left(\frac{q_1}{r_1} + \frac{q_2}{r_2}\right) $$ + +This is **superposition**, and for the potential it is nothing more than adding two numbers at every point — because $V$ is a scalar. Adding the two *fields* instead would mean a vector sum at every point in the cube. + +So the efficient route, and the reason the potential is worth defining at all, is: **add the potentials, then take one gradient at the very end.** The gradient is a linear operator, so this loses nothing. + +### Task 6 — build a dipole + +```{code-cell} ipython3 +# Task 6 +# A source and a sink. The two masked distances are given; build the physics +# on top of them. +# +# 1. Superpose the potentials: +Q at (-0.5, 0, 0) and -Q at (+0.5, 0, 0). +# Call the result V_dip. Remember this is scalar addition -- just a sum. +# 2. Take ONE gradient, and negate it, to get Ex_d, Ey_d, Ez_d. +# 3. Draw the z = 0 plane: +# fw.show_field_slice(X, Y, Z, Ex_d, Ey_d, background=V_dip, +# title=..., label="$V$ [V]") +# That puts the potential lines (colour) and the field lines (streamlines) +# on one picture. Follow it with plt.show(). +# +# Write your code here: + +r_plus = np.where(distance_to(X, Y, Z, -0.5, 0.0, 0.0) < 0.25, np.nan, + distance_to(X, Y, Z, -0.5, 0.0, 0.0)) +r_minus = np.where(distance_to(X, Y, Z, +0.5, 0.0, 0.0) < 0.25, np.nan, + distance_to(X, Y, Z, +0.5, 0.0, 0.0)) + + + +# --- self-check (leave this alone) --- +mid = np.abs(X) < 1e-9 # the plane x = 0, halfway between the charges +fw.check_shape("V_dip", V_dip, X.shape) +fw.check("V = 0 on the mid-plane", + np.nanmax(np.abs(V_dip[mid])) < 1e-6 * np.nanmax(np.abs(V_dip))) +fw.check("E on the mid-plane points from + to -", np.nanmean(Ex_d[mid]) > 0) +``` + +:::{admonition} Solution — Task 6 +:class: dropdown + +```python +# Task 6 solution +r_plus = np.where(distance_to(X, Y, Z, -0.5, 0.0, 0.0) < 0.25, np.nan, + distance_to(X, Y, Z, -0.5, 0.0, 0.0)) +r_minus = np.where(distance_to(X, Y, Z, +0.5, 0.0, 0.0) < 0.25, np.nan, + distance_to(X, Y, Z, +0.5, 0.0, 0.0)) + +V_dip = K * Q / r_plus + K * (-Q) / r_minus + +dVx, dVy, dVz = np.gradient(V_dip, dx, dy, dz) +Ex_d, Ey_d, Ez_d = -dVx, -dVy, -dVz + +fw.show_field_slice(X, Y, Z, Ex_d, Ey_d, background=V_dip, + title="Source and sink: potential (colour) and field lines", + label="$V$ [V]") +plt.show() +``` +::: + +:::{admonition} Look at the mid-plane before you move on +:class: tip + +Halfway between the two charges, at $x = 0$, the potential is **exactly zero** — the two contributions cancel. Yet the field there is not zero at all: it is at its strongest, pointing straight from the positive charge to the negative one. + +That catches people out every year. The field is the *slope* of the potential, not its value. A landscape can be at sea level and still be steep. +::: + +Now look at the same object in three dimensions. Positive and negative isosurfaces, drawn together and transparent: + +```{code-cell} ipython3 +lobe = np.nanpercentile(np.abs(V_dip), 97) +fw.show_isosurfaces(X, Y, Z, np.nan_to_num(V_dip), levels=[-lobe, -lobe/3, lobe/3, lobe], + colorscale="RdBu", opacity=0.3, + title="Equipotential surfaces of a dipole") +``` + +--- + +## Part 4 — Divergence: is anything being created here? + +The gradient took a scalar and gave back a vector. The divergence goes the other way — hand it a vector field, get back a scalar: + +$$ \nabla\cdot\mathbf{A} \;=\; \lim_{\Delta v \to 0}\frac{1}{\Delta v}\oint_S \mathbf{A}\cdot d\mathbf{s} \;=\; \frac{\partial A_x}{\partial x} + \frac{\partial A_y}{\partial y} + \frac{\partial A_z}{\partial z} $$ + +**Think of $\mathbf{A}$ as the velocity of a fluid.** Draw a small box anywhere. Measure how much fluid flows out through its walls, subtract how much flows in, and divide by the volume of the box. That number is the divergence: + +| $\nabla\cdot\mathbf{A}$ | Name | Picture | +| :---: | :--- | :--- | +| $> 0$ | **source** | a tap — more leaves than arrives | +| $< 0$ | **sink** | a drain — more arrives than leaves | +| $= 0$ | **solenoidal** | whatever flows in, flows out | + +### Task 7 — write the divergence + +```{code-cell} ipython3 +# Task 7 +# Write divergence(Ax, Ay, Az, dx, dy, dz) returning dAx/dx + dAy/dy + dAz/dz. +# +# You need one component from each of three np.gradient calls. Remember the +# order: np.gradient(Ax, dx, dy, dz)[0] is dAx/dx, index [1] is dAx/dy, and +# so on. You want [0] from the first, [1] from the second, [2] from the third. +# +# Write your code here: + + + +# --- self-check (leave this alone) --- +# A = x a_x + y a_y + z a_z is the position vector itself. Its divergence is +# 1 + 1 + 1 = 3, everywhere -- work it out on paper and confirm. +fw.check_close("div of the position vector = 3", + divergence(X, Y, Z, dx, dy, dz), 3.0, rtol=1e-6) +``` + +:::{admonition} Solution — Task 7 +:class: dropdown + +```python +# Task 7 solution +def divergence(Ax, Ay, Az, dx, dy, dz): + dAx_dx = np.gradient(Ax, dx, dy, dz)[0] + dAy_dy = np.gradient(Ay, dx, dy, dz)[1] + dAz_dz = np.gradient(Az, dx, dy, dz)[2] + return dAx_dx + dAy_dy + dAz_dz +``` +::: + +### Task 8 — three flows + +Three velocity fields. For each one: **sketch it in your head, predict the sign of the divergence, then measure.** Write your predictions down before running anything — the point of this task is the gap between intuition and the answer. + +| | Field $\mathbf{A}$ | What it looks like | +| :---: | :--- | :--- | +| **(a)** | $x\,\hat{\mathbf{a}}_x + y\,\hat{\mathbf{a}}_y + z\,\hat{\mathbf{a}}_z$ | flow rushing outward in all directions | +| **(b)** | $-y\,\hat{\mathbf{a}}_x + x\,\hat{\mathbf{a}}_y$ | fluid rotating about the $z$-axis | +| **(c)** | $x\,\hat{\mathbf{a}}_x - y\,\hat{\mathbf{a}}_y$ | stretching along $x$, squeezing along $y$ | + +```{code-cell} ipython3 +# Task 8 +# 1. Build the three fields as triples of arrays. np.zeros_like(X) is a +# useful zero component. +# 2. Compute the divergence of each with your Task 7 function, and print +# the mean of each. +# 3. Draw field (c) in the z = 0 plane with fw.show_field_slice(...) and +# look hard at it before reading the note below. +# +# Write your code here: + + + +# --- self-check (leave this alone) --- +fw.check_close("(a) div = 3", div_a, 3.0, rtol=1e-6) +fw.check_close("(b) div = 0 (rotation)", div_b + 1.0, 1.0, rtol=1e-6) +fw.check_close("(c) div = 0 (shear)", div_c + 1.0, 1.0, rtol=1e-6) +``` + +:::{admonition} Solution — Task 8 +:class: dropdown + +```python +# Task 8 solution +zero = np.zeros_like(X) + +Aa = (X, Y, Z) +Ab = (-Y, X, zero) +Ac = (X, -Y, zero) + +div_a = divergence(*Aa, dx, dy, dz) +div_b = divergence(*Ab, dx, dy, dz) +div_c = divergence(*Ac, dx, dy, dz) + +for name, d in [("(a) outward flow", div_a), ("(b) rotation", div_b), ("(c) shear", div_c)]: + print(f"{name:20s} div = {d.mean():+.3f}") + +fw.show_field_slice(X, Y, Z, *Ac[:2], title="(c) shear flow: divergence zero", density=1.1) +plt.show() +``` +::: + +:::{admonition} Field (c) is the one that costs marks +:class: warning + +Along the $x$-axis, field (c) rushes *outward*, away from the origin. It looks like a source. It is not: + +$$ \nabla\cdot\mathbf{A} = \frac{\partial}{\partial x}(x) + \frac{\partial}{\partial y}(-y) = 1 - 1 = 0 $$ + +Put a small box at the origin. Fluid pours out through the left and right walls — and pours in through the top and bottom at exactly the same rate. The parcel of fluid is stretched into a different **shape**, but its **volume** never changes. Nothing is created. + +*Arrows pointing apart* is not the same as *divergence*. Divergence is about net flux through a closed surface, and outflow in one direction can be cancelled exactly by inflow in another. Field (b) is the easy version of this idea; field (c) is the one that catches people. +::: + +### Task 9 — the divergence as a charge detector + +For the electric field, Maxwell's first equation says + +$$ \nabla\cdot\mathbf{E} = \frac{\rho}{\varepsilon_0} $$ + +which is a strong claim: **the divergence of $\mathbf{E}$, evaluated at a point, tells you the charge density at that point and nothing else.** Where there is no charge, $\mathbf{E}$ is solenoidal, however dramatically its arrows spread out. + +Let us check that, pointwise, on a real source. Not a point charge — a point charge is a mathematical idealisation with infinite density at one location, and no grid can represent that. Instead take a charge **smeared over a finite blob**, which is what any actual charged object is: + +$$ \rho(R) = \rho_0\,e^{-R^{2}/a^{2}}, \qquad a = 0.5\ \text{m} $$ + +Applying Gauss's law to a sphere of radius $R$ gives the field directly (you do not need to do this integral now — it is bookwork): + +$$ E_R(R) = \frac{\rho_0}{\varepsilon_0 R^{2}}\left[\frac{a^{3}\sqrt{\pi}}{4}\operatorname{erf}\!\left(\frac{R}{a}\right) - \frac{a^{2}R}{2}e^{-R^{2}/a^{2}}\right] $$ + +```{code-cell} ipython3 +from scipy.special import erf + +a, rho0 = 0.5, 1e-9 + +# Task 9 +# 1. Build rho = rho0 * exp(-r^2 / a^2) on the grid. +# 2. Build the radial field magnitude E_R from the formula above. Use +# Rs = np.maximum(r, 1e-9) in the denominators -- there is no singularity +# in this problem, but 0/0 at the exact centre still needs care. +# 3. Turn it into components: Ex_b = E_R * X/Rs, and likewise for y and z. +# 4. Take the divergence with your Task 7 function, and compare it against +# rho / epsilon_0 -- everywhere, including inside the blob. +# 5. Plot both, side by side, in the z = 0 plane. +# +# Write your code here: + + + +# --- self-check (leave this alone) --- +peak = np.nanmax(rho / epsilon_0) +err = np.nanmax(np.abs(div_blob[interior] - (rho / epsilon_0)[interior])) / peak +fw.check(f"div E = rho/eps0 pointwise (worst {err:.2%} of peak)", err < 0.05, + "check the component construction Ex = E_R * X/Rs") +``` + +:::{admonition} Solution — Task 9 +:class: dropdown + +```python +# Task 9 solution +Rs = np.maximum(r, 1e-9) +rho = rho0 * np.exp(-r**2 / a**2) + +E_R = rho0 / (epsilon_0 * Rs**2) * ( + (a**3 * np.sqrt(np.pi) / 4) * erf(Rs / a) - (a**2 * Rs / 2) * np.exp(-Rs**2 / a**2) +) +Ex_b, Ey_b, Ez_b = E_R * X / Rs, E_R * Y / Rs, E_R * Z / Rs + +div_blob = divergence(Ex_b, Ey_b, Ez_b, dx, dy, dz) + +fig, axes = plt.subplots(1, 2, figsize=(11, 4.4)) +fw.show_scalar_slice(X, Y, Z, div_blob, ax=axes[0], cmap="magma", + title=r"measured $\nabla\cdot\mathbf{E}$") +fw.show_scalar_slice(X, Y, Z, rho / epsilon_0, ax=axes[1], cmap="magma", + title=r"actual $\rho/\varepsilon_0$") +plt.show() + +print(f"peak of rho/eps0 : {np.nanmax(rho/epsilon_0):8.2f}") +print(f"peak of measured div: {np.nanmax(div_blob):8.2f}") +``` +::: + +:::{admonition} What you just did +:class: important + +The two pictures are the same picture. You never told the code where the charge was — you handed it a *field*, took derivatives of it, and the charge distribution came back out. + +That is Gauss's law working as an instrument rather than a formula. And notice where the divergence is zero: everywhere outside the blob, where the field is still large and still spreading vigorously. Strong field, zero divergence. The two ideas are unrelated. + +One more consequence, for later in the course. Another of Maxwell's equations is + +$$ \nabla\cdot\mathbf{B} = 0 $$ + +with no source term on the right at all. Run this same measurement on a magnetic field, anywhere in the universe, and you get zero — there are no magnetic monopoles. Field lines of $\mathbf{B}$ never begin and never end. +::: + +--- + +## Closing + +Today's chain, in one line: + +$$ \rho \;\longrightarrow\; V \;\xrightarrow{\ -\nabla\ }\; \mathbf{E} \;\xrightarrow{\ \nabla\cdot\ }\; \rho/\varepsilon_0 $$ + +- **Gradient** — scalar in, vector out. Points along steepest increase, perpendicular to the level surfaces. +- **Divergence** — vector in, scalar out. Measures what is being created, and nothing else. + +### What is still missing + +Go back to field **(b)**, the rotation. Its divergence is zero everywhere, so by that measure it is indistinguishable from a field doing nothing whatsoever. But it plainly *is* doing something — it circulates, and every streamline closes on itself. + +Divergence cannot see circulation. The operator that can is the **curl** — the third of the three operators this chapter is named after. + +Keep `fwtools.py` to hand: the later labs in this chapter reuse the same helpers and the same grid conventions. + +### Homework + +**Exercise A — a heat source in a room.** Replace the spherical blob with a **square** one: a flat rectangular heater, say $1.0 \times 0.6$ m in the $z=0$ plane. Build its temperature field by superposing point sources over a grid of positions covering the rectangle, exactly as you superposed two charges in Task 6. Then: + +- Plot the isosurfaces. Close to the heater they should be rounded rectangles; far away they should become spheres. Why? +- Heat flux is $\mathbf{q} = -k\nabla T$ — the same minus sign, the same reason. Compute it. +- Check that $\nabla\cdot\mathbf{q} \approx 0$ away from the heater. What does that statement mean physically, in a room at steady state? + +**Exercise B — where does the $1/r$ come from?** Task 2 showed $|\nabla r| = 1$ and Task 4 showed $|\nabla(1/r)| = 1/r^2$. Using $\nabla g(r) = \dfrac{dg}{dr}\hat{\mathbf{a}}_R$, derive both on paper, and then work out which power $n$ in $r^{n}$ would make the field fall off as $1/r^{3}$. diff --git a/book/_toc.yml b/book/_toc.yml index 51c03cd..300a786 100644 --- a/book/_toc.yml +++ b/book/_toc.yml @@ -14,6 +14,7 @@ parts: # - file: 1_gradient_divergence_curl/gradient.md # - file: 1_gradient_divergence_curl/divergence.md # - file: 1_gradient_divergence_curl/curl.md + - file: 1_gradient_divergence_curl/labs/week01-grad-div.md - caption: Potential Fields chapters: - file: 2_potential_fields/introduction/intro.md From a2d154ce19236043961c06008ae8e5185b733d5f Mon Sep 17 00:00:00 2001 From: ARS183 <1028762817@qq.com> Date: Fri, 28 Aug 2026 00:15:43 +0200 Subject: [PATCH 02/17] Add flux and the divergence theorem to the Week 1 lab --- .../labs/fwtools.py | 61 +- .../labs/week01-grad-div.md | 532 ++++++++++-------- 2 files changed, 364 insertions(+), 229 deletions(-) diff --git a/book/1_gradient_divergence_curl/labs/fwtools.py b/book/1_gradient_divergence_curl/labs/fwtools.py index 02bb4dc..ee47b7a 100644 --- a/book/1_gradient_divergence_curl/labs/fwtools.py +++ b/book/1_gradient_divergence_curl/labs/fwtools.py @@ -20,8 +20,9 @@ __all__ = [ "make_grid_3d", "z0_index", "slice_z0", + "box_indices", "area_integral", "volume_integral", "show_isosurfaces", "show_cones", "show_scalar_slice", "show_field_slice", - "check", "check_shape", "check_close", + "check", "check_shape", "check_close", "check_scalar", ] # -------------------------------------------------------------------------- @@ -58,6 +59,53 @@ def slice_z0(F: np.ndarray, Z: np.ndarray) -> np.ndarray: return F[:, :, z0_index(Z)] +# -------------------------------------------------------------------------- +# Integration over grid-aligned boxes and faces +# +# These evaluate the integrals in the definition of the divergence and in the +# divergence theorem. They are quadrature boilerplate: the trapezoidal weights +# below simply stop the end samples from being counted as full cells. +# -------------------------------------------------------------------------- + +def _trapezoid_weights(n: int) -> np.ndarray: + w = np.ones(n) + w[0] = w[-1] = 0.5 + return w + + +def box_indices(X: np.ndarray, half_width: float): + """Index range (i0, i1) of the sub-cube |x|, |y|, |z| <= ``half_width``. + + The same pair works on all three axes because the grid is cubic. The + returned indices are snapped to the nearest grid planes, so ask for a + half-width that is a multiple of the spacing (0.6, 1.0 and 1.4 m are + exact on the default 61-point grid) if you want the box you asked for. + """ + axis = X[:, 0, 0] + i0 = int(np.argmin(np.abs(axis + half_width))) + i1 = int(np.argmin(np.abs(axis - half_width))) + return i0, i1 + + +def area_integral(F2: np.ndarray, da: float, db: float) -> float: + """Integrate a 2-D array of samples over the rectangle it spans. + + Use it on one face of a box to evaluate that face's contribution to a + surface integral. + """ + F2 = np.asarray(F2, float) + wa, wb = _trapezoid_weights(F2.shape[0]), _trapezoid_weights(F2.shape[1]) + return float(np.nansum(F2 * wa[:, None] * wb[None, :]) * da * db) + + +def volume_integral(F3: np.ndarray, dx: float, dy: float, dz: float) -> float: + """Integrate a 3-D array of samples over the box it spans.""" + F3 = np.asarray(F3, float) + wx, wy, wz = (_trapezoid_weights(m) for m in F3.shape) + w = wx[:, None, None] * wy[None, :, None] * wz[None, None, :] + return float(np.nansum(F3 * w) * dx * dy * dz) + + # -------------------------------------------------------------------------- # 3-D views (plotly) # -------------------------------------------------------------------------- @@ -226,3 +274,14 @@ def check_close(label: str, got, want, rtol=0.05, where=None) -> None: check(f"{label}: worst error {worst:.2%}", worst < rtol, f"worst relative error {worst:.2%} exceeds {rtol:.0%}. Check your " f"np.gradient call -- did you pass dx, dy, dz, and in that order?") + + +def check_scalar(label: str, got: float, want: float, rtol: float = 0.01, + unit: str = "") -> None: + """Compare two single numbers and report the relative discrepancy.""" + got, want = float(got), float(want) + rel = abs(got - want) / max(abs(want), 1e-30) + check(f"{label}: {got:.4g}{unit} vs {want:.4g}{unit} ({rel:.2%} apart)", + rel < rtol, + f"these should agree to better than {rtol:.0%}. Check the sign of " + f"each face, and that every face uses its own outward normal.") diff --git a/book/1_gradient_divergence_curl/labs/week01-grad-div.md b/book/1_gradient_divergence_curl/labs/week01-grad-div.md index 5dc7974..72bb738 100644 --- a/book/1_gradient_divergence_curl/labs/week01-grad-div.md +++ b/book/1_gradient_divergence_curl/labs/week01-grad-div.md @@ -9,11 +9,8 @@ kernelspec: language: python name: python3 mystnb: - # This page is a workbook: its task cells contain `___` blanks that raise - # NameError by design, and every later cell depends on variables those tasks - # define. Executing it at build time would fail the build, so it is switched - # off for this page alone -- the book-wide setting is untouched. Readers run - # the code themselves with Live Code. + # Workbook page: the task cells contain `___` blanks by design, so it must + # not be executed at build time. Readers run it themselves with Live Code. execution_mode: 'off' --- @@ -22,25 +19,27 @@ mystnb: :::{admonition} Computer lab :class: note -A practical companion to the lecture notes on the gradient and the divergence. Here you build both operators yourself, in three dimensions, and look at what they do. +A practical companion to the lecture notes on the gradient and the divergence. You build both operators yourself, in three dimensions, and then use them to recover a charge distribution from nothing but its field. ::: -## How this lab works +## Learning objectives + +By the end of this session you should be able to: -**You write the code.** Not one line at a time into someone else's function — you write the fields, the operators and the checks. Each task states a physical question, gives you the steps, and ends with a self-check you can run. +- **Read a gradient off a picture.** Explain why $\nabla f$ is perpendicular to the level surfaces of $f$, why $\nabla r = \hat{\mathbf{a}}_R$, and why the single minus sign in $\mathbf{E} = -\nabla V$ is the step from geometry to physics. +- **Distinguish "arrows spreading apart" from divergence.** Compute $\nabla\cdot\mathbf{A}$ for fields that look like sources and are not, and justify the answer with a flux argument rather than with algebra. +- **Use Gauss's law as a measurement.** Verify $\nabla\cdot\mathbf{E} = \rho/\varepsilon_0$ pointwise, verify the divergence theorem $\oint_S\mathbf{E}\cdot d\mathbf{s} = \int_v \nabla\cdot\mathbf{E}\,dv$ numerically, and explain what happens to both when the source shrinks to a point. -What we supply is the *plotting*, in a module called `fwtools`. Drawing a transparent isosurface in plotly is fiddly and teaches you nothing about electromagnetism, so that part is done for you. Your time goes on physics. +## How this lab works -**Nine tasks, about ten minutes each.** After each one there is a dropdown solution. Open it *after* you have tried, or when you are stuck for more than a couple of minutes — being stuck on syntax is not the point of this lab. +**You write the code.** Each task states a physical question, gives you the steps, and ends with a self-check you can run. What we supply is the *plotting*, in a module called `fwtools` — drawing a transparent isosurface teaches you nothing about electromagnetism, so your time goes on physics instead. -**A running theme.** Watch for the moment in Part 2 where a single minus sign turns a piece of geometry into a piece of physics. +**Nine tasks.** The scaffolding thins out as the afternoon goes on: the first tasks have blanks to fill, the last ones give you an empty cell and a list of steps. After each task there is a dropdown solution — open it *after* you have tried, or when you have been stuck on syntax for more than a couple of minutes. --- ## Part 0 — Setup -Run these two cells. The first imports what we need; the second builds the cube of sample points that everything else lives on. - ```{code-cell} ipython3 import sys, pathlib @@ -48,9 +47,7 @@ import numpy as np import matplotlib.pyplot as plt from scipy.constants import epsilon_0 -# Live Code runs Python in your browser, on Pyodide. Pyodide bundles numpy, -# scipy and matplotlib, but not plotly -- so fetch it when it is missing. -# Running locally, plotly is already installed and this branch never executes. +# --- Live Code housekeeping; nothing here is part of the physics ------------ try: import plotly.io as pio except ModuleNotFoundError: @@ -59,9 +56,6 @@ except ModuleNotFoundError: await micropip.install("plotly") import plotly.io as pio -# plotly refuses to display a figure unless it can find nbformat >= 4.2, which -# it uses only to decide that it is running inside a notebook. Pyodide has no -# nbformat, so give it one. try: import nbformat # noqa: F401 except ModuleNotFoundError: @@ -69,58 +63,56 @@ except ModuleNotFoundError: try: await micropip.install("nbformat") except Exception: - # nbformat pulls in jsonschema, which may not be installable here. - # The version string is the only part plotly actually reads. _nb = types.ModuleType("nbformat") _nb.__version__ = "5.10.4" sys.modules["nbformat"] = _nb -# fwtools holds the plotting helpers. Where it sits depends on how you are -# running: your own folder in JupyterLab, or the browser's virtual filesystem -# under Live Code. Look in the likely places rather than assume. -for _p in (".", "week-01-Grad-Div", "/week-01-Grad-Div", "book/week-01-Grad-Div"): +for _p in (".", "week-01-Grad-Div", "/week-01-Grad-Div", "book/1_gradient_divergence_curl/labs"): if (pathlib.Path(_p) / "fwtools.py").exists(): sys.path.insert(0, _p) break try: import fwtools as fw except ModuleNotFoundError: - from pyodide.http import pyfetch # Live Code only - _r = await pyfetch("fwtools.py") # sits beside this page + from pyodide.http import pyfetch + _r = await pyfetch("fwtools.py") pathlib.Path("fwtools.py").write_bytes(await _r.bytes()) import fwtools as fw pio.renderers.default = "plotly_mimetype+notebook" +# --------------------------------------------------------------------------- -K = 1.0 / (4.0 * np.pi * epsilon_0) # the Coulomb constant, 8.99e9 V*m/C -Q = 1e-9 # 1 nC, a convenient test charge +K = 1.0 / (4.0 * np.pi * epsilon_0) # Coulomb constant, 8.99e9 V*m/C +Q = 1e-9 # 1 nC test charge print(f"epsilon_0 = {epsilon_0:.4e} F/m") print(f"K = {K:.4e} V*m/C") ``` +:::{admonition} What that middle block is for +:class: dropdown + +Live Code runs Python inside your browser using Pyodide. Pyodide ships numpy, scipy and matplotlib but not plotly, and plotly in turn refuses to draw anything unless it can find a package called `nbformat` — which it uses only to convince itself that it is running in a notebook. The block installs both, then locates `fwtools.py`, whose position depends on whether you are in JupyterLab or in the browser's virtual filesystem. Running locally, none of those branches execute. +::: + +Everything in this lab lives on one cube of sample points. + ```{code-cell} ipython3 X, Y, Z, dx, dy, dz = fw.make_grid_3d(n=61, L=2.0) print(f"grid shape {X.shape}, spacing {dx:.4f} m, {X.size:,} sample points") -print(f"X[i,j,k] = x[i] -> X[-1, 0, 0] = {X[-1, 0, 0]:.1f} m") +print(f"domain: {X.min():.1f} m to {X.max():.1f} m on each axis") ``` -:::{admonition} Why `indexing='ij'`, and why you should care +:::{admonition} Grid convention — two rules for the whole afternoon :class: tip -`np.meshgrid` has two conventions. The default, `indexing='xy'`, puts **y on axis 0** — so `np.gradient` hands back the *y*-derivative first, and half of all numerical field bugs come from that one fact. +The grid is built with `indexing='ij'`, so axis 0 is $x$, axis 1 is $y$, axis 2 is $z$. -We use `indexing='ij'` instead, so axis 0 is x, axis 1 is y, axis 2 is z: +1. **Derivatives come back in coordinate order:** `np.gradient(f, dx, dy, dz)` returns $\partial f/\partial x$, $\partial f/\partial y$, $\partial f/\partial z$. No transposes. +2. **Always pass the spacings.** Omit them and the derivative is silently wrong by a factor of $1/\Delta x = 15$. -```python -dfdx, dfdy, dfdz = np.gradient(f, dx, dy, dz) # in the order you expect -``` - -Two rules that follow, and that you will use in every task today: - -1. **Always pass the spacings** `dx, dy, dz`. Leave them out and `np.gradient` assumes a spacing of 1, making every derivative wrong by a factor of 15. -2. **Derivatives come back in coordinate order.** No transposes, no surprises. +Numpy's default is `indexing='xy'`, which returns the $y$-derivative first. That one fact is the origin of a large fraction of all numerical field bugs. ::: --- @@ -136,13 +128,7 @@ $$ r(x,y,z) = \sqrt{(x-x_0)^2 + (y-y_0)^2 + (z-z_0)^2} $$ ### Task 1 — build the distance field ```{code-cell} ipython3 -# Task 1 -# The distance from every grid point to a source at (x0, y0, z0) is -# r = sqrt( (x-x0)^2 + (y-y0)^2 + (z-z0)^2 ) -# Replace each ___ below. Note that X, Y, Z are whole arrays, so writing -# (X - x0)**2 squares every point at once -- no loops anywhere today. -# -# Write your code here: +# Task 1 -- distance from a source at (x0, y0, z0) to every point of the grid. def distance_to(X, Y, Z, x0=0.0, y0=0.0, z0=0.0): return np.sqrt(___ + ___ + ___) @@ -162,7 +148,6 @@ fw.check("r = 2 m at (0,2,0)", np.isclose(r[c, -1, c], 2.0)) :class: dropdown ```python -# Task 1 solution def distance_to(X, Y, Z, x0=0.0, y0=0.0, z0=0.0): return np.sqrt((X - x0)**2 + (Y - y0)**2 + (Z - z0)**2) @@ -171,149 +156,128 @@ r = distance_to(X, Y, Z) ``` ::: -### What does this field look like? - -A surface on which $r$ takes one fixed value is called an **isosurface**, or level set — the three-dimensional version of a contour line on a map. Draw a few, with transparency, so you can see through the outer ones to the inner ones. +A surface on which $r$ takes one fixed value is an **isosurface**, or level set — the three-dimensional version of a contour line on a map. Draw a few, with transparency, so the inner ones show through the outer ones. ```{code-cell} ipython3 fw.show_isosurfaces(X, Y, Z, r, levels=[0.5, 1.0, 1.5], title="Isosurfaces of the distance function r") ``` -**Drag the figure to rotate it.** They are spheres, nested inside one another — which is only to say that "all the points 1 metre from here" *is* a sphere. Nothing deeper than that. But it is worth seeing, because in a moment the gradient is going to be perpendicular to these surfaces, and that will not be a coincidence. +**Drag the figure to rotate it.** They are nested spheres — which is only to say that "all the points 1 metre from here" *is* a sphere. Nothing deeper than that. But keep the picture in mind: in a moment the gradient will turn out to be perpendicular to these surfaces, and that will not be a coincidence. ### Task 2 — the gradient of the distance -Now compute $\nabla r$. Before you run it, predict two things and write them down: +Compute $\nabla r$. Before you run anything, predict two things and write them down: **which way** the arrows point, and **how long** they are. -- **which way** do you expect the arrows to point? -- **how long** do you expect them to be? +Then test the prediction quantitatively. The outward unit radial vector is $\hat{\mathbf{a}}_R = (x\,\hat{\mathbf{a}}_x + y\,\hat{\mathbf{a}}_y + z\,\hat{\mathbf{a}}_z)/r$, so the radial part of any vector field $\mathbf{A}$ is $\mathbf{A}\cdot\hat{\mathbf{a}}_R$. If $\nabla r$ is *purely* radial, that projection recovers its full magnitude and nothing is left over. ```{code-cell} ipython3 +# The outward unit radial vector, used again later. +Rs = np.maximum(r, 1e-12) # 0/0 at the source is not a lesson +aRx, aRy, aRz = X / Rs, Y / Rs, Z / Rs + # Task 2 -# np.gradient returns one array per axis. Because our grid uses -# indexing='ij', they arrive in the order (d/dx, d/dy, d/dz) -- and you must -# pass the three spacings, or every derivative is wrong by a factor of 15. -# -# Fill in the blanks, then look hard at the printed magnitudes. -# -# Write your code here: +# 1. grad r, as three components. +# 2. Its magnitude. +# 3. Its projection onto a_R. +# 4. Draw it, then rotate the figure and compare with the spheres above. grx, gry, grz = np.gradient(___, ___, ___, ___) grad_r_mag = np.sqrt(___ + ___ + ___) -for name, idx in [("(2,0,0)", (-1, c, c)), ("(0,2,0)", (c, -1, c))]: - print(f"|grad r| at {name} = {grad_r_mag[idx]:.4f}") +radial_part = grx * ___ + gry * ___ + grz * ___ + +fw.show_cones(X, Y, Z, ___, ___, ___, step=8, + title="grad r -- unit vectors pointing away from the source") # --- self-check (leave this alone) --- band = (r > 0.4) & (r < 1.6) fw.check_shape("grad r", grx, X.shape) fw.check_close("|grad r| = 1 everywhere", grad_r_mag, 1.0, rtol=0.05, where=band) +fw.check_close("grad r is purely radial", radial_part, 1.0, rtol=0.05, where=band) ``` :::{admonition} Solution — Task 2 :class: dropdown ```python -# Task 2 solution grx, gry, grz = np.gradient(r, dx, dy, dz) grad_r_mag = np.sqrt(grx**2 + gry**2 + grz**2) +radial_part = grx * aRx + gry * aRy + grz * aRz -for (i, j, k), name in [((-1, c, c), "(2,0,0)"), ((c, -1, c), "(0,2,0)")]: - print(f"|grad r| at {name} = {grad_r_mag[i, j, k]:.4f}") -print(f"|grad r| median away from the origin = " +print(f"|grad r| median in 0.4 < r < 1.6 m : " f"{np.median(grad_r_mag[(r > 0.4) & (r < 1.6)]):.4f}") + +fw.show_cones(X, Y, Z, grx, gry, grz, step=8, + title="grad r -- unit vectors pointing away from the source") ``` ::: :::{admonition} The magnitude is 1. Everywhere. :class: important -That is not a numerical accident, and it is worth a moment. +That is not a numerical accident. -Walk one metre directly away from the source point. Your distance from it increases by exactly one metre. The steepest possible rate of change of $r$ is therefore $1$ metre per metre — a slope of 1 — no matter where you are standing. - -So the gradient of the distance function is a **unit vector pointing radially outward**: +Walk one metre directly away from the source point and your distance from it increases by exactly one metre. The steepest possible rate of change of $r$ is therefore 1 metre per metre — a slope of 1 — no matter where you are standing. So $$ \nabla r = \hat{\mathbf{a}}_R $$ -This is the cleanest possible illustration of what a gradient *is*: the direction of steepest increase, with a length equal to that rate of increase. Here the direction is "away from the source" and the rate is 1. -::: +This is the cleanest illustration of what a gradient *is*: a direction of steepest increase, carrying a length equal to that rate of increase. -### Task 3 — see it +The second check says something else worth having. The arrows are perpendicular to the spheres because moving *along* a sphere does not change $r$ at all — and a direction that produces no change contributes nothing to the gradient. That argument holds for every scalar field: **$\nabla f$ is always normal to the level surfaces of $f$.** +::: -```{code-cell} ipython3 -# Task 3 -# Draw the gradient field. Fill in the three components, then rotate the -# figure and compare it with the isosurfaces above: every arrow should -# pierce the spheres at a right angle. -# -# Write your code here: +:::{admonition} A rule you will use twice more today +:class: tip -fw.show_cones(X, Y, Z, ___, ___, ___, step=8, - title="grad r -- unit vectors pointing away from the source") -``` +Any field that depends on position only through $r$ — call it $g(r)$ — has level surfaces that are spheres, so its gradient must be radial. Its magnitude is just the ordinary derivative: -:::{admonition} Solution — Task 3 -:class: dropdown +$$ \nabla g(r) = \frac{dg}{dr}\,\hat{\mathbf{a}}_R $$ -```python -# Task 3 solution -fw.show_cones(X, Y, Z, grx, gry, grz, step=8, - title="grad r -- unit vectors pointing away from the source") -``` - -The arrows are perpendicular to the spheres because moving *along* a sphere does not change $r$ at all. If a direction produces no change, the gradient has no component along it — so the gradient must be entirely perpendicular to the level surface. That argument works for every scalar field, not just this one. +Task 2 is the case $g = r$, giving $\nabla r = 1\cdot\hat{\mathbf{a}}_R$. **Use this rule to predict the next two tasks before you run them.** ::: --- ## Part 2 — Invert it, and watch the arrows turn round -Now the function the physics actually uses: not the distance, but **one over** the distance. +Now the function the physics actually uses: not the distance, but **one over** the distance, -$$ f(r) = \frac{1}{r} $$ +$$ f(r) = \frac{1}{r}, \qquad\text{so}\qquad \nabla f = \frac{d}{dr}\!\left(\frac{1}{r}\right)\hat{\mathbf{a}}_R = -\frac{1}{r^{2}}\,\hat{\mathbf{a}}_R $$ -Same spheres as isosurfaces — $f$ is constant wherever $r$ is constant. But the *ordering* has been turned inside out: $f$ is now largest near the source and decays to nothing far away. +Same spheres as isosurfaces — $f$ is constant wherever $r$ is constant. But the *ordering* has been turned inside out: $f$ is now largest near the source and decays to nothing far away. Predict what that does to the arrows, then check the prediction against the formula above, then measure it. -### Task 4 — the gradient of the inverse distance +### Task 3 — the gradient of the inverse distance ```{code-cell} ipython3 -# Task 4 -# Now the same two steps for f = 1/r. The masking line is given, because -# dividing by zero at the origin is a detail rather than a lesson. The rest -# is yours -- it is the same shape as Task 2. -# -# 1. Take the gradient of f. Call the components fx, fy, fz. -# 2. Build its magnitude, f_mag. -# 3. Print f_mag against 1/r^2 at r = 0.6, 1.0 and 1.5 m. -# 4. Predict the DIRECTION first, then draw it: -# fw.show_cones(X, Y, Z, fx, fy, fz, step=8, normalise=True, title=...) -# -# Write your code here: - +# The mask keeps the singularity at r = 0 off the grid. Everything within +# 0.25 m of the source becomes NaN and is simply not measured. r_masked = np.where(r < 0.25, np.nan, r) f = 1.0 / r_masked +# Task 3 +# 1. grad f, as components fx, fy, fz; then its magnitude f_mag. +# 2. Print f_mag against the predicted 1/r^2 at r = 0.6, 1.0 and 1.5 m. +# 3. Draw it with normalise=True (direction only -- the magnitude spans +# three orders of magnitude across this box and would swamp the picture). + +# Write your code here: + # --- self-check (leave this alone) --- interior = np.zeros_like(r, dtype=bool) -interior[2:-2, 2:-2, 2:-2] = True # np.gradient is less accurate at the edges +interior[2:-2, 2:-2, 2:-2] = True # np.gradient is one-sided at the edges outside = (r > 0.5) & interior fw.check_close("|grad(1/r)| = 1/r^2", f_mag, 1.0 / r_masked**2, rtol=0.05, where=outside) fw.check("grad(1/r) points inward at (1,0,0)", fx[-1 - 15, c, c] < 0) ``` -:::{admonition} Solution — Task 4 +:::{admonition} Solution — Task 3 :class: dropdown ```python -# Task 4 solution -r_masked = np.where(r < 0.25, np.nan, r) -f = 1.0 / r_masked - fx, fy, fz = np.gradient(f, dx, dy, dz) f_mag = np.sqrt(fx**2 + fy**2 + fz**2) @@ -333,36 +297,32 @@ The arrows have reversed. Same spheres, same source, opposite direction: $$ \nabla r = +\hat{\mathbf{a}}_R, \qquad\qquad \nabla\!\left(\frac{1}{r}\right) = -\frac{1}{r^{2}}\,\hat{\mathbf{a}}_R $$ -Nothing about space changed. What changed is **which way the function climbs**. $r$ grows as you move away, so $\nabla r$ points away. $1/r$ grows as you move *closer*, so $\nabla(1/r)$ points inward — steeply, as $1/r^2$, because $1/r$ climbs ever faster near the source. +Nothing about space changed. What changed is **which way the function climbs**. And the steepness changed too: $1/r$ climbs ever faster as you approach the source, so its gradient grows as $1/r^2$ rather than staying at 1. -A gradient always points along the direction of maximum increase of its own function. It knows nothing about sources, sinks, charges or fields; it only knows uphill. +A gradient knows nothing about sources, sinks, charges or fields. It only knows uphill. ::: -### Task 5 — from geometry to physics - -Here is where the physics enters, and it enters as a single minus sign. +### Task 4 — from geometry to physics -The electric potential of a point charge $q$ is the inverse-distance function with a constant in front: +Here the physics enters, and it enters as a single minus sign. The electric potential of a point charge $q$ is the inverse-distance function with a constant in front, -$$ V(r) = \frac{1}{4\pi\varepsilon_0}\frac{q}{r} $$ +$$ V(r) = \frac{1}{4\pi\varepsilon_0}\frac{q}{r}\quad[\text{V}], $$ -and the electric field is defined as +and the electric field is *defined* as -$$ \mathbf{E} = -\nabla V $$ +$$ \mathbf{E} = -\nabla V \quad[\text{V/m}]. $$ -You already know what $\nabla V$ does: it points *inward*, uphill towards the charge. The minus sign turns it round. **The field points downhill** — which is exactly what a positive test charge released from rest would do, running away from a positive source and losing potential energy as it goes. +You already know what $\nabla V$ does: it points inward, uphill towards the charge. The minus sign turns it round, so **the field points downhill** — which is exactly the way a positive test charge released from rest would move, losing potential energy as it goes. ```{code-cell} ipython3 -# Task 5 -# The potential is given. Everything after it is yours. -# -# 1. Get E = -grad V. Call the components Ex, Ey, Ez. -# 2. Build E_mag, and compare it against the analytic K*Q/r^2 at a few radii. +V = K * Q / r_masked + +# Task 4 +# 1. E = -grad V, as components Ex, Ey, Ez; then E_mag. +# 2. Compare E_mag against the analytic K*Q/r^2 at a few radii, in V/m. # 3. Draw it with normalise=True and confirm it points OUTWARD for q > 0. -# -# Write your code here: -V = K * Q / r_masked +# Write your code here: @@ -372,13 +332,10 @@ fw.check_close("|E| = q/(4 pi eps0 r^2)", E_mag, K * Q / r_masked**2, fw.check("E points outward at (1,0,0)", Ex[-1 - 15, c, c] > 0) ``` -:::{admonition} Solution — Task 5 +:::{admonition} Solution — Task 4 :class: dropdown ```python -# Task 5 solution -V = K * Q / r_masked - dVdx, dVdy, dVdz = np.gradient(V, dx, dy, dz) Ex, Ey, Ez = -dVdx, -dVdy, -dVdz E_mag = np.sqrt(Ex**2 + Ey**2 + Ez**2) @@ -393,61 +350,60 @@ fw.show_cones(X, Y, Z, Ex, Ey, Ez, step=8, normalise=True, ``` ::: +:::{admonition} Why bother with $V$ at all? +:class: tip + +$V$ is a scalar: one number per point, no direction to keep track of. $\mathbf{E}$ is a vector: three. Anything you can do once on $V$ and then differentiate is cheaper — in arithmetic and in bookkeeping — than doing it three times on $\mathbf{E}$. + +Part 3 is the first payoff, and it is the reason the potential is worth defining in the first place. +::: + --- -## Part 3 — Two sources: a source and a sink +## Part 3 — Two sources: superposition -One charge is symmetric enough to be boring. Put down two. +One charge is symmetric enough to be boring. Put down two: $$ V_{\text{total}} = \frac{1}{4\pi\varepsilon_0}\left(\frac{q_1}{r_1} + \frac{q_2}{r_2}\right) $$ -This is **superposition**, and for the potential it is nothing more than adding two numbers at every point — because $V$ is a scalar. Adding the two *fields* instead would mean a vector sum at every point in the cube. +**Superposition** for the potential is nothing more than adding two numbers at every point, because $V$ is a scalar. Adding the two *fields* instead would mean a vector sum at every point in the cube. -So the efficient route, and the reason the potential is worth defining at all, is: **add the potentials, then take one gradient at the very end.** The gradient is a linear operator, so this loses nothing. +Since $\nabla$ is a linear operator, $-\nabla(V_1 + V_2) = \mathbf{E}_1 + \mathbf{E}_2$ exactly. So the efficient route is: **add the potentials, then take one gradient at the very end.** Nothing is lost. -### Task 6 — build a dipole +### Task 5 — build a dipole ```{code-cell} ipython3 -# Task 6 -# A source and a sink. The two masked distances are given; build the physics -# on top of them. -# -# 1. Superpose the potentials: +Q at (-0.5, 0, 0) and -Q at (+0.5, 0, 0). -# Call the result V_dip. Remember this is scalar addition -- just a sum. -# 2. Take ONE gradient, and negate it, to get Ex_d, Ey_d, Ez_d. -# 3. Draw the z = 0 plane: -# fw.show_field_slice(X, Y, Z, Ex_d, Ey_d, background=V_dip, -# title=..., label="$V$ [V]") -# That puts the potential lines (colour) and the field lines (streamlines) -# on one picture. Follow it with plt.show(). -# -# Write your code here: - +# Distances to two sources placed on the x-axis, both masked as before. r_plus = np.where(distance_to(X, Y, Z, -0.5, 0.0, 0.0) < 0.25, np.nan, distance_to(X, Y, Z, -0.5, 0.0, 0.0)) r_minus = np.where(distance_to(X, Y, Z, +0.5, 0.0, 0.0) < 0.25, np.nan, distance_to(X, Y, Z, +0.5, 0.0, 0.0)) +# Task 5 +# 1. Superpose the potentials of +Q at (-0.5, 0, 0) and -Q at (+0.5, 0, 0) +# into V_dip. Scalar addition -- just a sum. +# 2. Take ONE gradient, negate it: Ex_d, Ey_d, Ez_d. +# 3. Draw the z = 0 plane, potential as colour and field as streamlines: +# fw.show_field_slice(X, Y, Z, Ex_d, Ey_d, background=V_dip, +# title=..., label="$V$ [V]") +# then plt.show(). + +# Write your code here: + # --- self-check (leave this alone) --- -mid = np.abs(X) < 1e-9 # the plane x = 0, halfway between the charges +mid = np.abs(X) < 1e-9 # the plane x = 0, halfway between them fw.check_shape("V_dip", V_dip, X.shape) fw.check("V = 0 on the mid-plane", np.nanmax(np.abs(V_dip[mid])) < 1e-6 * np.nanmax(np.abs(V_dip))) fw.check("E on the mid-plane points from + to -", np.nanmean(Ex_d[mid]) > 0) ``` -:::{admonition} Solution — Task 6 +:::{admonition} Solution — Task 5 :class: dropdown ```python -# Task 6 solution -r_plus = np.where(distance_to(X, Y, Z, -0.5, 0.0, 0.0) < 0.25, np.nan, - distance_to(X, Y, Z, -0.5, 0.0, 0.0)) -r_minus = np.where(distance_to(X, Y, Z, +0.5, 0.0, 0.0) < 0.25, np.nan, - distance_to(X, Y, Z, +0.5, 0.0, 0.0)) - V_dip = K * Q / r_plus + K * (-Q) / r_minus dVx, dVy, dVz = np.gradient(V_dip, dx, dy, dz) @@ -465,10 +421,10 @@ plt.show() Halfway between the two charges, at $x = 0$, the potential is **exactly zero** — the two contributions cancel. Yet the field there is not zero at all: it is at its strongest, pointing straight from the positive charge to the negative one. -That catches people out every year. The field is the *slope* of the potential, not its value. A landscape can be at sea level and still be steep. +The field is the *slope* of the potential, not its value. A landscape can be at sea level and still be steep. Notice also what the picture shows about direction: the streamlines cross the coloured contours at right angles everywhere, which is Task 2's normality result showing up in a field you did not construct radially. ::: -Now look at the same object in three dimensions. Positive and negative isosurfaces, drawn together and transparent: +The same object in three dimensions — positive and negative equipotential surfaces together, drawn transparent: ```{code-cell} ipython3 lobe = np.nanpercentile(np.abs(V_dip), 97) @@ -481,11 +437,11 @@ fw.show_isosurfaces(X, Y, Z, np.nan_to_num(V_dip), levels=[-lobe, -lobe/3, lobe/ ## Part 4 — Divergence: is anything being created here? -The gradient took a scalar and gave back a vector. The divergence goes the other way — hand it a vector field, get back a scalar: +The gradient took a scalar and returned a vector. The divergence goes the other way — hand it a vector field, get back a scalar: $$ \nabla\cdot\mathbf{A} \;=\; \lim_{\Delta v \to 0}\frac{1}{\Delta v}\oint_S \mathbf{A}\cdot d\mathbf{s} \;=\; \frac{\partial A_x}{\partial x} + \frac{\partial A_y}{\partial y} + \frac{\partial A_z}{\partial z} $$ -**Think of $\mathbf{A}$ as the velocity of a fluid.** Draw a small box anywhere. Measure how much fluid flows out through its walls, subtract how much flows in, and divide by the volume of the box. That number is the divergence: +Read the definition on the left, not the formula on the right. **Think of $\mathbf{A}$ as the velocity of a fluid.** Draw a small box anywhere. Measure how much fluid flows out through its walls, subtract how much flows in, divide by the volume of the box, and shrink the box. That number is the divergence: | $\nabla\cdot\mathbf{A}$ | Name | Picture | | :---: | :--- | :--- | @@ -493,32 +449,30 @@ $$ \nabla\cdot\mathbf{A} \;=\; \lim_{\Delta v \to 0}\frac{1}{\Delta v}\oint_S \m | $< 0$ | **sink** | a drain — more arrives than leaves | | $= 0$ | **solenoidal** | whatever flows in, flows out | -### Task 7 — write the divergence +### Task 6 — write the divergence ```{code-cell} ipython3 -# Task 7 -# Write divergence(Ax, Ay, Az, dx, dy, dz) returning dAx/dx + dAy/dy + dAz/dz. -# -# You need one component from each of three np.gradient calls. Remember the -# order: np.gradient(Ax, dx, dy, dz)[0] is dAx/dx, index [1] is dAx/dy, and -# so on. You want [0] from the first, [1] from the second, [2] from the third. -# +# Task 6 +# Write divergence(Ax, Ay, Az, dx, dy, dz) returning +# dAx/dx + dAy/dy + dAz/dz. You need one component from each of three +# separate gradient calls -- the x-derivative of Ax, the y-derivative of +# Ay, the z-derivative of Az. The cross terms are not part of a divergence. + # Write your code here: # --- self-check (leave this alone) --- -# A = x a_x + y a_y + z a_z is the position vector itself. Its divergence is -# 1 + 1 + 1 = 3, everywhere -- work it out on paper and confirm. +# The position vector A = x a_x + y a_y + z a_z has divergence 1 + 1 + 1 = 3 +# everywhere. Confirm that on paper before you trust the number. fw.check_close("div of the position vector = 3", divergence(X, Y, Z, dx, dy, dz), 3.0, rtol=1e-6) ``` -:::{admonition} Solution — Task 7 +:::{admonition} Solution — Task 6 :class: dropdown ```python -# Task 7 solution def divergence(Ax, Ay, Az, dx, dy, dz): dAx_dx = np.gradient(Ax, dx, dy, dz)[0] dAy_dy = np.gradient(Ay, dx, dy, dz)[1] @@ -527,9 +481,9 @@ def divergence(Ax, Ay, Az, dx, dy, dz): ``` ::: -### Task 8 — three flows +### Task 7 — three flows -Three velocity fields. For each one: **sketch it in your head, predict the sign of the divergence, then measure.** Write your predictions down before running anything — the point of this task is the gap between intuition and the answer. +Three velocity fields. For each: **sketch it in your head, predict the sign of the divergence, then measure.** Write the predictions down first — the point of this task is the gap between intuition and the answer. | | Field $\mathbf{A}$ | What it looks like | | :---: | :--- | :--- | @@ -538,14 +492,12 @@ Three velocity fields. For each one: **sketch it in your head, predict the sign | **(c)** | $x\,\hat{\mathbf{a}}_x - y\,\hat{\mathbf{a}}_y$ | stretching along $x$, squeezing along $y$ | ```{code-cell} ipython3 -# Task 8 -# 1. Build the three fields as triples of arrays. np.zeros_like(X) is a -# useful zero component. -# 2. Compute the divergence of each with your Task 7 function, and print -# the mean of each. +# Task 7 +# 1. Build the three fields as triples of arrays. +# 2. Take the divergence of each with your Task 6 function; print the mean. # 3. Draw field (c) in the z = 0 plane with fw.show_field_slice(...) and # look hard at it before reading the note below. -# + # Write your code here: @@ -556,11 +508,10 @@ fw.check_close("(b) div = 0 (rotation)", div_b + 1.0, 1.0, rtol=1e-6) fw.check_close("(c) div = 0 (shear)", div_c + 1.0, 1.0, rtol=1e-6) ``` -:::{admonition} Solution — Task 8 +:::{admonition} Solution — Task 7 :class: dropdown ```python -# Task 8 solution zero = np.zeros_like(X) Aa = (X, Y, Z) @@ -588,22 +539,22 @@ $$ \nabla\cdot\mathbf{A} = \frac{\partial}{\partial x}(x) + \frac{\partial}{\par Put a small box at the origin. Fluid pours out through the left and right walls — and pours in through the top and bottom at exactly the same rate. The parcel of fluid is stretched into a different **shape**, but its **volume** never changes. Nothing is created. -*Arrows pointing apart* is not the same as *divergence*. Divergence is about net flux through a closed surface, and outflow in one direction can be cancelled exactly by inflow in another. Field (b) is the easy version of this idea; field (c) is the one that catches people. +*Arrows pointing apart* is not the same as *divergence*. Divergence is net flux through a closed surface, and outflow in one direction can be cancelled exactly by inflow in another. Field (b) is the easy version of this idea; field (c) is the one that catches people. ::: -### Task 9 — the divergence as a charge detector +### Task 8 — the divergence as a charge detector -For the electric field, Maxwell's first equation says +Maxwell's first equation says $$ \nabla\cdot\mathbf{E} = \frac{\rho}{\varepsilon_0} $$ -which is a strong claim: **the divergence of $\mathbf{E}$, evaluated at a point, tells you the charge density at that point and nothing else.** Where there is no charge, $\mathbf{E}$ is solenoidal, however dramatically its arrows spread out. +which is a strong claim: **the divergence of $\mathbf{E}$ at a point tells you the charge density at that point and nothing else.** Wherever there is no charge, $\mathbf{E}$ is solenoidal, however dramatically its arrows spread out. -Let us check that, pointwise, on a real source. Not a point charge — a point charge is a mathematical idealisation with infinite density at one location, and no grid can represent that. Instead take a charge **smeared over a finite blob**, which is what any actual charged object is: +Test that pointwise on a real source. Not a point charge — that is an idealisation with infinite density at one location, and no grid can hold it. Take instead a charge **smeared over a finite blob**, which is what any actual charged object is: $$ \rho(R) = \rho_0\,e^{-R^{2}/a^{2}}, \qquad a = 0.5\ \text{m} $$ -Applying Gauss's law to a sphere of radius $R$ gives the field directly (you do not need to do this integral now — it is bookwork): +Applying Gauss's law to a sphere of radius $R$ gives the field directly (bookwork — you do not need to do this integral now): $$ E_R(R) = \frac{\rho_0}{\varepsilon_0 R^{2}}\left[\frac{a^{3}\sqrt{\pi}}{4}\operatorname{erf}\!\left(\frac{R}{a}\right) - \frac{a^{2}R}{2}e^{-R^{2}/a^{2}}\right] $$ @@ -612,16 +563,17 @@ from scipy.special import erf a, rho0 = 0.5, 1e-9 -# Task 9 -# 1. Build rho = rho0 * exp(-r^2 / a^2) on the grid. -# 2. Build the radial field magnitude E_R from the formula above. Use -# Rs = np.maximum(r, 1e-9) in the denominators -- there is no singularity -# in this problem, but 0/0 at the exact centre still needs care. -# 3. Turn it into components: Ex_b = E_R * X/Rs, and likewise for y and z. -# 4. Take the divergence with your Task 7 function, and compare it against -# rho / epsilon_0 -- everywhere, including inside the blob. -# 5. Plot both, side by side, in the z = 0 plane. -# +# Task 8 +# 1. rho = rho0 * exp(-r^2 / a^2) on the grid. +# 2. E_R from the formula above, using Rs in the denominators. +# 3. Turn the radial magnitude into components along a_R: +# Ex_b = E_R * aRx, and likewise for y and z. +# 4. div_blob = divergence(...), and compare it against rho / epsilon_0 +# everywhere -- including inside the source. +# 5. Plot both, side by side, in the z = 0 plane: +# fig, axes = plt.subplots(1, 2, figsize=(11, 4.4)) +# fw.show_scalar_slice(..., ax=axes[0], cmap="magma", title=...) + # Write your code here: @@ -630,21 +582,19 @@ a, rho0 = 0.5, 1e-9 peak = np.nanmax(rho / epsilon_0) err = np.nanmax(np.abs(div_blob[interior] - (rho / epsilon_0)[interior])) / peak fw.check(f"div E = rho/eps0 pointwise (worst {err:.2%} of peak)", err < 0.05, - "check the component construction Ex = E_R * X/Rs") + "check the component construction Ex_b = E_R * aRx") ``` -:::{admonition} Solution — Task 9 +:::{admonition} Solution — Task 8 :class: dropdown ```python -# Task 9 solution -Rs = np.maximum(r, 1e-9) rho = rho0 * np.exp(-r**2 / a**2) E_R = rho0 / (epsilon_0 * Rs**2) * ( (a**3 * np.sqrt(np.pi) / 4) * erf(Rs / a) - (a**2 * Rs / 2) * np.exp(-Rs**2 / a**2) ) -Ex_b, Ey_b, Ez_b = E_R * X / Rs, E_R * Y / Rs, E_R * Z / Rs +Ex_b, Ey_b, Ez_b = E_R * aRx, E_R * aRy, E_R * aRz div_blob = divergence(Ex_b, Ey_b, Ez_b, dx, dy, dz) @@ -663,15 +613,124 @@ print(f"peak of measured div: {np.nanmax(div_blob):8.2f}") :::{admonition} What you just did :class: important -The two pictures are the same picture. You never told the code where the charge was — you handed it a *field*, took derivatives of it, and the charge distribution came back out. +The two pictures are the same picture. You never told the code where the charge was — you handed it a *field*, differentiated it, and the charge distribution came back out. That is Gauss's law working as an instrument rather than a formula. + +Notice also where the divergence is zero: everywhere outside the blob, where the field is still large and still spreading vigorously. **Strong field, zero divergence.** The two ideas are unrelated. +::: + +--- + +## Part 5 — Flux, and the divergence theorem + +Part 4 used the *differential* form of Gauss's law, which is local: it compares two numbers at the same point. The *integral* form is global, and connects a volume to the surface that encloses it: + +$$ \oint_S \mathbf{E}\cdot d\mathbf{s} \;=\; \int_v \nabla\cdot\mathbf{E}\;dv \;=\; \frac{Q_{\text{enc}}}{\varepsilon_0} $$ -That is Gauss's law working as an instrument rather than a formula. And notice where the divergence is zero: everywhere outside the blob, where the field is still large and still spreading vigorously. Strong field, zero divergence. The two ideas are unrelated. +The first equality is the **divergence theorem**, and it is pure vector calculus — true for any well-behaved vector field, charge or no charge. The second is the physics. Together they say something remarkable: measuring $\mathbf{E}$ on a closed surface tells you how much charge is inside, and *nothing whatever* about how that charge is arranged, or about any charge outside. + +You will now evaluate all three quantities independently and see them agree. + +Take $S$ to be a cube of half-width $h$ centred on the origin, with faces on grid planes. On the $+x$ face the outward normal is $+\hat{\mathbf{a}}_x$, so that face contributes $\int\!\!\int E_x\,dy\,dz$; on the $-x$ face the normal is $-\hat{\mathbf{a}}_x$ and the same integral enters with a minus sign. Six faces, three pairs. + +### Task 9 — close the surface + +```{code-cell} ipython3 +# `fw.area_integral(F2, da, db)` integrates a 2-D array over the face it +# spans; `fw.volume_integral(F3, dx, dy, dz)` does the same over a box. +# `fw.box_indices(X, h)` gives the index range of the cube |x|,|y|,|z| <= h. +# +# Task 9 (using the blob field Ex_b, Ey_b, Ez_b from Task 8) +# 1. For h = 0.6, 1.0 and 1.4 m, get i0, i1 = fw.box_indices(X, h) and +# s = slice(i0, i1 + 1). +# 2. Surface integral. The +x face is Ex_b[i1, s, s] and the -x face is +# Ex_b[i0, s, s]; their contribution is the difference of the two area +# integrals, with dy and dz as the spacings. Add the y and z pairs. +# Wrap this in a function closed_box_flux(Ax, Ay, Az, half_width) -- +# the next section reuses it on a different field. +# 3. Volume integral of div_blob over the same cube: div_blob[s, s, s]. +# 4. Enclosed charge: volume integral of rho over the same cube, then +# divide by epsilon_0. +# 5. Print all three, in V*m, for each h. They should agree. + +# Write your code here: + + + +# --- self-check (leave this alone) --- +i0, i1 = fw.box_indices(X, 1.0) +s = slice(i0, i1 + 1) +fw.check_scalar("closed-surface flux = Q_enc/eps0", flux_1m, + fw.volume_integral(rho[s, s, s], dx, dy, dz) / epsilon_0, + rtol=0.01, unit=" V*m") +fw.check_scalar("divergence theorem: surface = volume", flux_1m, + fw.volume_integral(div_blob[s, s, s], dx, dy, dz), + rtol=0.01, unit=" V*m") +``` + +:::{admonition} Solution — Task 9 +:class: dropdown + +```python +def closed_box_flux(Ax, Ay, Az, half_width): + """Net outward flux of a vector field through a cube of half-width h.""" + i0, i1 = fw.box_indices(X, half_width) + s = slice(i0, i1 + 1) + return ( + fw.area_integral(Ax[i1, s, s], dy, dz) - fw.area_integral(Ax[i0, s, s], dy, dz) + + fw.area_integral(Ay[s, i1, s], dx, dz) - fw.area_integral(Ay[s, i0, s], dx, dz) + + fw.area_integral(Az[s, s, i1], dx, dy) - fw.area_integral(Az[s, s, i0], dx, dy) + ) + + +print(f"{'h [m]':>6} {'surface':>12} {'volume':>12} {'Q_enc/eps0':>12}") +for h in (0.6, 1.0, 1.4): + i0, i1 = fw.box_indices(X, h) + s = slice(i0, i1 + 1) + surf = closed_box_flux(Ex_b, Ey_b, Ez_b, h) + vol = fw.volume_integral(div_blob[s, s, s], dx, dy, dz) + qenc = fw.volume_integral(rho[s, s, s], dx, dy, dz) / epsilon_0 + print(f"{h:6.1f} {surf:12.3f} {vol:12.3f} {qenc:12.3f}") + +flux_1m = closed_box_flux(Ex_b, Ey_b, Ez_b, 1.0) +``` +::: + +:::{admonition} Three routes, one number +:class: important + +The three columns are three genuinely different calculations. The first never looks inside the box — it only samples $\mathbf{E}$ on a surface. The second never looks at the surface — it differentiates the field throughout the interior. The third never looks at the field at all — it integrates the charge you put there. They agree to a fraction of a percent. + +Notice how the number grows with $h$ and then stops: once the cube contains essentially all of the Gaussian blob, enlarging it further adds surface area but no charge, and the flux settles at $Q_{\text{total}}/\varepsilon_0$. Charge outside a closed surface contributes exactly nothing to the flux through it — the extra field lines it sends in through one wall come straight out through another. +::: + +### And now shrink the source to a point + +Run the same surface integral on the point-charge field from Task 4 — the one whose divergence you could never measure at the origin, because you had to mask it away. + +```{code-cell} ipython3 +for h in (0.6, 1.0, 1.4): + print(f"h = {h:.1f} m : flux = {closed_box_flux(Ex, Ey, Ez, h):8.3f} V*m" + f" (Q/eps0 = {Q / epsilon_0:.3f} V*m)") + +shell = interior & (r > 0.5) & (r < 1.6) +div_point = divergence(np.nan_to_num(Ex), np.nan_to_num(Ey), np.nan_to_num(Ez), dx, dy, dz) +scale = (E_mag / Rs)[shell] # the natural size of a derivative of E here +print(f"\n|div E| away from the origin: median {np.median(np.abs(div_point[shell]) / scale):.2%} " + f"of |E|/r -- zero to within the accuracy of the grid") +``` + +:::{admonition} Where did the charge go? +:class: important + +Every box returns $Q/\varepsilon_0$. Yet the divergence is zero at every point you are able to measure, and the boxes have nothing in common except the origin. + +So the entire source sits at a single point, and $\nabla\cdot\mathbf{E}$ there is not a large number — it is not a number at all. What $\rho$ has become is a **Dirac delta**: zero everywhere, infinite at one point, with a finite integral $q$. This is precisely the situation the integral form was made for, and the reason it survives where the differential form breaks down. One more consequence, for later in the course. Another of Maxwell's equations is -$$ \nabla\cdot\mathbf{B} = 0 $$ +$$ \nabla\cdot\mathbf{B} = 0 \qquad\Longleftrightarrow\qquad \oint_S \mathbf{B}\cdot d\mathbf{s} = 0 \ \ \text{for every closed } S $$ -with no source term on the right at all. Run this same measurement on a magnetic field, anywhere in the universe, and you get zero — there are no magnetic monopoles. Field lines of $\mathbf{B}$ never begin and never end. +with no source term on the right at all. Run this measurement on a magnetic field, around any surface anywhere in the universe, and you get zero — there are no magnetic monopoles. Field lines of $\mathbf{B}$ never begin and never end. ::: --- @@ -682,23 +741,40 @@ Today's chain, in one line: $$ \rho \;\longrightarrow\; V \;\xrightarrow{\ -\nabla\ }\; \mathbf{E} \;\xrightarrow{\ \nabla\cdot\ }\; \rho/\varepsilon_0 $$ -- **Gradient** — scalar in, vector out. Points along steepest increase, perpendicular to the level surfaces. -- **Divergence** — vector in, scalar out. Measures what is being created, and nothing else. +- **Gradient** — scalar in, vector out. Points along steepest increase, perpendicular to the level surfaces, with length equal to the rate of increase. +- **Divergence** — vector in, scalar out. Net flux per unit volume: what is being created here, and nothing else. + +### The same two operators, elsewhere in ECT + +Electrostatics is the convenient place to *learn* this pair, not the only place to use it. Every row below is a potential, its gradient, and a statement about sources — and the numerical machinery you wrote today applies unchanged to all of them: + +| System | Potential | Field | Source equation | +| :--- | :--- | :--- | :--- | +| Electrostatics | $V$ [V] | $\mathbf{E} = -\nabla V$ | $\nabla\cdot\mathbf{E} = \rho/\varepsilon_0$ | +| Gravitation | $\Phi$ [J/kg] | $\mathbf{g} = -\nabla \Phi$ | $\nabla\cdot\mathbf{g} = -4\pi G\rho_m$ | +| Heat conduction | $T$ [K] | $\mathbf{q} = -k\nabla T$ | $\nabla\cdot\mathbf{q} = 0$ (steady, no sources) | +| Groundwater flow | $h$ [m] | $\mathbf{q} = -K\nabla h$ | $\nabla\cdot\mathbf{q} = 0$ (steady, incompressible) | + +The minus signs are all the same minus sign: heat flows from hot to cold, water flows from high head to low, a positive charge falls from high potential to low. Flow runs downhill, and the gradient points uphill. + +The last two rows are why a solenoidal field matters so much in practice. $\nabla\cdot\mathbf{q} = 0$ in an aquifer is not an approximation of convenience — it is conservation of water written locally. ### What is still missing -Go back to field **(b)**, the rotation. Its divergence is zero everywhere, so by that measure it is indistinguishable from a field doing nothing whatsoever. But it plainly *is* doing something — it circulates, and every streamline closes on itself. +Go back to field **(b)**, the rotation. Its divergence is zero everywhere, so by that measure it is indistinguishable from a field doing nothing at all. But it plainly *is* doing something — it circulates, and every streamline closes on itself. -Divergence cannot see circulation. The operator that can is the **curl** — the third of the three operators this chapter is named after. +Divergence cannot see circulation. The operator that can is the **curl**, the third of the three this chapter is named after. Keep `fwtools.py` to hand: the later labs in this chapter reuse the same helpers and the same grid conventions. ### Homework -**Exercise A — a heat source in a room.** Replace the spherical blob with a **square** one: a flat rectangular heater, say $1.0 \times 0.6$ m in the $z=0$ plane. Build its temperature field by superposing point sources over a grid of positions covering the rectangle, exactly as you superposed two charges in Task 6. Then: +**Exercise A — a heat source in a room.** Replace the spherical blob with a flat rectangular heater, say $1.0 \times 0.6$ m in the $z = 0$ plane, built by superposing point sources over the rectangle exactly as you superposed two charges in Task 5. Then: + +- Plot the isosurfaces. Close to the plate they should be rounded rectangles; far away they should become spheres. Why does the shape forget its source? +- Compute the heat flux $\mathbf{q} = -k\nabla T$ — the same minus sign, the same reason. +- Check that $\nabla\cdot\mathbf{q} \approx 0$ away from the heater, and that the closed-surface flux through a box containing the plate is *not* zero. State what each result means physically for a room at steady state. -- Plot the isosurfaces. Close to the heater they should be rounded rectangles; far away they should become spheres. Why? -- Heat flux is $\mathbf{q} = -k\nabla T$ — the same minus sign, the same reason. Compute it. -- Check that $\nabla\cdot\mathbf{q} \approx 0$ away from the heater. What does that statement mean physically, in a room at steady state? +**Exercise B — the $r^n$ family.** Using $\nabla g(r) = \dfrac{dg}{dr}\hat{\mathbf{a}}_R$, derive $|\nabla r| = 1$ and $|\nabla(1/r)| = 1/r^2$ on paper, then find which power $n$ in $r^{n}$ gives a field falling off as $1/r^{3}$. -**Exercise B — where does the $1/r$ come from?** Task 2 showed $|\nabla r| = 1$ and Task 4 showed $|\nabla(1/r)| = 1/r^2$. Using $\nabla g(r) = \dfrac{dg}{dr}\hat{\mathbf{a}}_R$, derive both on paper, and then work out which power $n$ in $r^{n}$ would make the field fall off as $1/r^{3}$. +**Exercise C — why $1/r^2$, and not any other power.** Compute the flux of $\hat{\mathbf{a}}_R/r^{n}$ through spheres of two different radii. Show that the flux is independent of radius only for $n = 2$, and connect that to the fact that we live in three dimensions. This is the deepest reason Coulomb's law has the exponent it has. From 0e4826e0f5769ff4dc68af0fa002928fe94e7bb3 Mon Sep 17 00:00:00 2001 From: ARS183 <1028762817@qq.com> Date: Sat, 29 Aug 2026 01:24:06 +0200 Subject: [PATCH 03/17] Refine Week 1 lab: R notation, convergence study, shared plot scales --- .../labs/fwtools.py | 361 +++++++++++--- .../labs/week01-grad-div.md | 463 ++++++++++++------ 2 files changed, 600 insertions(+), 224 deletions(-) diff --git a/book/1_gradient_divergence_curl/labs/fwtools.py b/book/1_gradient_divergence_curl/labs/fwtools.py index ee47b7a..2b71943 100644 --- a/book/1_gradient_divergence_curl/labs/fwtools.py +++ b/book/1_gradient_divergence_curl/labs/fwtools.py @@ -19,36 +19,16 @@ import plotly.graph_objects as go __all__ = [ - "make_grid_3d", "z0_index", "slice_z0", + "z0_index", "slice_z0", "box_indices", "area_integral", "volume_integral", "show_isosurfaces", "show_cones", "show_scalar_slice", "show_field_slice", "check", "check_shape", "check_close", "check_scalar", ] # -------------------------------------------------------------------------- -# Grid +# Grid helpers (the grid itself is built in the open, on the lab page) # -------------------------------------------------------------------------- -def make_grid_3d(n: int = 61, L: float = 2.0): - """A cube of sample points on [-L, L]^3 with n points per side. - - Returns - ------- - X, Y, Z : (n, n, n) float arrays - Coordinates, built with indexing='ij' so that X[i, j, k] = x[i], - Y[i, j, k] = y[j] and Z[i, j, k] = z[k]. - dx, dy, dz : float - Uniform spacings. np.gradient needs these -- omit them and it assumes - a spacing of 1, making every derivative wrong by a constant factor. - """ - if n % 2 == 0: - raise ValueError("use an odd n so that the grid contains the origin exactly") - a = np.linspace(-L, L, n) - X, Y, Z = np.meshgrid(a, a, a, indexing="ij") - h = a[1] - a[0] - return X, Y, Z, h, h, h - - def z0_index(Z: np.ndarray) -> int: """Index k of the z = 0 plane in an indexing='ij' grid.""" return int(np.argmin(np.abs(Z[0, 0, :]))) @@ -91,87 +71,294 @@ def area_integral(F2: np.ndarray, da: float, db: float) -> float: """Integrate a 2-D array of samples over the rectangle it spans. Use it on one face of a box to evaluate that face's contribution to a - surface integral. + surface integral. The rule is the trapezoidal one, second order in the + spacing: on the fields in this lab the flux error falls from 0.17% at + n = 21 to 0.018% at n = 61. + + Raises if any sample is NaN. A masked sample silently integrated as zero + returns a plausible and wrong number -- which is what happens if you put + a face inside a region you have masked out. """ F2 = np.asarray(F2, float) + _reject_masked(F2, "This face passes through masked samples") wa, wb = _trapezoid_weights(F2.shape[0]), _trapezoid_weights(F2.shape[1]) - return float(np.nansum(F2 * wa[:, None] * wb[None, :]) * da * db) + return float(np.sum(F2 * wa[:, None] * wb[None, :]) * da * db) def volume_integral(F3: np.ndarray, dx: float, dy: float, dz: float) -> float: - """Integrate a 3-D array of samples over the box it spans.""" + """Integrate a 3-D array of samples over the box it spans. + + Trapezoidal, second order, and it raises on masked samples for the same + reason ``area_integral`` does. + """ F3 = np.asarray(F3, float) + _reject_masked(F3, "This box contains masked samples") wx, wy, wz = (_trapezoid_weights(m) for m in F3.shape) w = wx[:, None, None] * wy[None, :, None] * wz[None, None, :] - return float(np.nansum(F3 * w) * dx * dy * dz) + return float(np.sum(F3 * w) * dx * dy * dz) + + +def _reject_masked(F, what): + n = int(np.count_nonzero(~np.isfinite(F))) + if n: + raise ValueError( + f"{what} ({n} of {F.size} are NaN or infinite). Integrating them " + f"as zero would return a plausible but wrong number. Move the " + f"surface outside the masked region, or unmask the field.") # -------------------------------------------------------------------------- # 3-D views (plotly) # -------------------------------------------------------------------------- -def show_isosurfaces(X, Y, Z, F, levels, *, title="", opacity=0.35, - colorscale="Viridis", show_caps=False, size=620, step=2): +# Directional shading. Without it plotly lights an isosurface almost flatly +# and a nest of transparent spheres reads as a set of flat rings; the +# specular highlight and limb darkening are what make it look like a ball. +_LIGHTING = dict(ambient=0.35, diffuse=0.9, specular=0.5, roughness=0.4, fresnel=0.2) +_LIGHTPOSITION = dict(x=100, y=200, z=200) + + +def show_isosurfaces(X, Y, Z, F, levels, *, title="", label="", opacity=0.3, + colorscale="Viridis", show_caps=False, size=620, step=2, + opacity_slider=True, slice_z=None): """Draw one or more isosurfaces (level sets) of a scalar field F. An isosurface is the set of points where F takes one fixed value -- the - 3-D analogue of a contour line. Transparency lets you see the inner - surfaces through the outer ones, so pass a list of levels and look at the - nesting. + 3-D analogue of a contour line. Pass an **evenly spaced** list of levels + and look at the nesting; anything else is refused, because plotly draws + evenly spaced surfaces between the extremes and would quietly move them. + + Parameters that matter for seeing the shape + ------------------------------------------- + opacity_slider : bool + Adds a slider under the figure. Drag it up towards 1 and the outermost + surface becomes a solid, shaded ball; drag it down towards 0.1 and it + turns to glass so the inner surfaces show through. Sweeping it is the + quickest way to convince yourself these are shells and not discs. + label : str + Colorbar title. Give it the physical quantity and its unit. + **Plotly does not render LaTeX here.** Colorbar titles accept plain + text plus a small HTML subset (````, ````, ````), so + write ``"|\u2207r| [-]"`` and ``"[m-2]"`` with Unicode + symbols -- a ``$...$`` label silently comes out as garbled glyphs. + The matplotlib helpers below are the opposite: mathtext works there. + slice_z : float or None + If given, also draw a filled cut plane at that value of z, exposing + the interior. A strong depth cue, at the cost of hiding part of the + nesting. """ - levels = np.atleast_1d(np.asarray(levels, dtype=float)) + levels = np.sort(np.atleast_1d(np.asarray(levels, dtype=float))) + # plotly draws surface_count EVENLY SPACED surfaces between isomin and + # isomax; it never sees the individual values. Unevenly spaced levels + # would therefore be silently redrawn at the wrong values, so refuse them + # rather than return a picture that lies. + if levels.size > 2: + gaps = np.diff(levels) + if not np.allclose(gaps, gaps[0], rtol=1e-6): + drawn = np.linspace(levels[0], levels[-1], levels.size) + raise ValueError( + f"levels must be evenly spaced: plotly would draw " + f"{np.round(drawn, 4).tolist()} instead of " + f"{np.round(levels, 4).tolist()}. Use an evenly spaced set, " + f"or call this once per level.") # Subsample before handing the volume to plotly. A full 61^3 grid embeds # ~12 MB of JSON per figure; every other point looks identical on screen. sl = (slice(None, None, step),) * 3 X, Y, Z, F = X[sl], Y[sl], Z[sl], np.asarray(F)[sl] - fig = go.Figure( - go.Isosurface( - x=X.ravel(), y=Y.ravel(), z=Z.ravel(), value=np.asarray(F).ravel(), - isomin=float(levels.min()), isomax=float(levels.max()), - surface_count=int(levels.size), opacity=opacity, - colorscale=colorscale, showscale=True, - caps=dict(x_show=show_caps, y_show=show_caps, z_show=show_caps), - ) + trace = go.Isosurface( + x=X.ravel(), y=Y.ravel(), z=Z.ravel(), value=np.asarray(F).ravel(), + isomin=float(levels.min()), isomax=float(levels.max()), + surface_count=int(levels.size), opacity=opacity, + colorscale=colorscale, showscale=True, + colorbar=dict(title=label, len=0.7), + lighting=_LIGHTING, lightposition=_LIGHTPOSITION, + caps=dict(x_show=show_caps, y_show=show_caps, z_show=show_caps), ) - _style_3d(fig, title, size) - return fig - - -def show_cones(X, Y, Z, Ax, Ay, Az, *, step=8, title="", sizeref=0.6, - colorscale="Blues", size=620, normalise=False): - """Draw a 3-D vector field as a lattice of cones (arrows). - - Only every ``step``-th sample in each direction is drawn -- a full grid of - cones is an unreadable haystack. Set ``normalise=True`` to show direction - only, with every cone the same length; this is often clearer for fields - whose magnitude varies over orders of magnitude. + if slice_z is not None: + trace.slices = dict(z=dict(show=True, locations=[float(slice_z)])) + fig = go.Figure(trace) + _style_3d(fig, title, size, bottom_margin=55 if opacity_slider else 0) + if opacity_slider: + _add_opacity_slider(fig, opacity) + return _display(fig) + + +def _add_opacity_slider(fig, current): + """A client-side opacity control: no kernel needed once the figure exists.""" + values = [round(0.1 * i, 1) for i in range(1, 11)] + active = int(np.argmin([abs(v - current) for v in values])) + fig.update_layout(sliders=[dict( + active=active, + currentvalue=dict(prefix="opacity: ", font=dict(size=13)), + pad=dict(t=8, b=8), len=0.7, x=0.15, y=0, + steps=[dict(method="restyle", args=[{"opacity": v}], label=f"{v:.1f}") + for v in values], + )]) + + +def show_cones(X, Y, Z, Ax, Ay, Az, *, step=8, title="", label="", size=620, + normalise=False, length=None, head=0.35, colorscale="Viridis", + slider=True, width=4, log_colour=None): + """Draw a 3-D vector field as arrows: a shaft with a barbed head. + + Every arrow is built from line segments -- a shaft, plus four barbs swept + back from the tip. plotly's ``go.Cone`` is not used: a cone takes both its + size and its colour from the norm of the vector it is given, so size and + colour cannot be set independently, and a field whose magnitudes are all + close to 1 comes out with heads larger than the box. + + Only every ``step``-th sample in each direction is drawn; an arrow at every + grid point is an unreadable haystack. + + Parameters + ---------- + label : str + Colorbar title, e.g. ``"|E| [V/m]"``. Defaults to a generic + ``|A|``; give it the real quantity and unit so the reader can tell + the tasks apart. Plotly renders no LaTeX here -- see the note in + ``show_isosurfaces``. + normalise : bool + Draw every arrow the same length, showing direction only. Use it for + fields whose magnitude spans orders of magnitude, where true-to-scale + arrows leave a few giants and a lot of invisible dust. The magnitude is + not lost -- it is still in the colour. + length : float or None + Length of the longest arrow, in metres. Defaults to 0.85 of the + spacing between drawn arrows, so a full-length arrow almost touches + its neighbour. + head : float + Fraction of an arrow taken up by its head. + slider : bool + Add a size slider under the figure, scaling whole arrows (head + included) between 0.5x and 2x. + log_colour : bool or None + Colour by log10|A| rather than |A|. ``None`` decides automatically and + switches over once the magnitude spans more than a factor of 50: on a + linear scale a $1/r^2$ field puts all but a handful of arrows into the + bottom percent of the colour range, where they are indistinguishable. """ sl = (slice(None, None, step),) * 3 x, y, z = X[sl].ravel(), Y[sl].ravel(), Z[sl].ravel() - u, v, w = np.asarray(Ax)[sl].ravel(), np.asarray(Ay)[sl].ravel(), np.asarray(Az)[sl].ravel() + u = np.asarray(Ax)[sl].ravel() + v = np.asarray(Ay)[sl].ravel() + w = np.asarray(Az)[sl].ravel() finite = np.isfinite(u) & np.isfinite(v) & np.isfinite(w) x, y, z, u, v, w = (a[finite] for a in (x, y, z, u, v, w)) - if normalise: - mag = np.sqrt(u**2 + v**2 + w**2) - mag[mag == 0] = 1.0 - u, v, w = u / mag, v / mag, w / mag - - fig = go.Figure( - go.Cone(x=x, y=y, z=z, u=u, v=v, w=w, - sizemode="scaled", sizeref=sizeref, anchor="tail", - colorscale=colorscale, showscale=True, - colorbar=dict(title="|A|")), + mag = np.sqrt(u**2 + v**2 + w**2) + safe = np.maximum(mag, 1e-30) + ux, uy, uz = u / safe, v / safe, w / safe # unit direction + + spacing = float(abs(X[step, 0, 0] - X[0, 0, 0])) if X.shape[0] > step else 1.0 + base = 0.85 * spacing if length is None else float(length) + rel = np.ones_like(mag) if normalise else mag / max(float(mag.max()), 1e-30) + + positive = mag[mag > 0] + if log_colour is None: + log_colour = (positive.size > 0 + and float(positive.max()) > 50.0 * float(positive.min())) + name = label or "|A|" + if log_colour: + cval = np.log10(np.maximum(mag, float(positive.min()))) + clabel = f"log10 {name}" + else: + cval, clabel = mag, name + + px, py, pz = _arrow_lines(x, y, z, ux, uy, uz, rel * base, head) + fig = go.Figure(go.Scatter3d( + x=px, y=py, z=pz, mode="lines", hoverinfo="skip", showlegend=False, + line=dict(color=np.tile(np.repeat(cval, 3), _SEGMENTS_PER_ARROW), + colorscale=colorscale, width=width, + cmin=float(cval.min()), cmax=float(cval.max()), + showscale=True, colorbar=dict(title=clabel, len=0.7)), + )) + _style_3d(fig, title, size, bottom_margin=75 if slider else 0) + # Pin the box to the sampled volume; without this the arrows themselves + # drive the autorange and the domain silently grows. + fig.update_scenes( + xaxis=dict(range=[float(X.min()), float(X.max())], title="x [m]"), + yaxis=dict(range=[float(Y.min()), float(Y.max())], title="y [m]"), + zaxis=dict(range=[float(Z.min()), float(Z.max())], title="z [m]"), ) - _style_3d(fig, title, size) - return fig + if slider: + _add_arrow_slider(fig, x, y, z, ux, uy, uz, rel, base, head) + return _display(fig) + + +_SEGMENTS_PER_ARROW = 5 # one shaft, four barbs + +def _arrow_lines(x, y, z, ux, uy, uz, lengths, head): + """One polyline per segment, all arrows in one flat pair of arrays. + + Segments are separated by NaN, which plotly renders as a break. The four + barbs are swept back from the tip in two mutually perpendicular planes, so + the head reads as a head from any viewing angle. + """ + n = x.size + tx, ty, tz = x + ux * lengths, y + uy * lengths, z + uz * lengths + + d = np.stack([ux, uy, uz], axis=1) + # A reference direction not parallel to d, so the cross product is stable. + ref = np.where(np.abs(uz)[:, None] < 0.9, + np.array([0.0, 0.0, 1.0]), np.array([1.0, 0.0, 0.0])) + p = np.cross(d, ref) + p /= np.maximum(np.linalg.norm(p, axis=1, keepdims=True), 1e-30) + q = np.cross(d, p) + + barb = lengths * head + spread = 0.45 + xs, ys, zs = [], [], [] + + def add(x0, y0, z0, x1, y1, z1): + for a, b, out in ((x0, x1, xs), (y0, y1, ys), (z0, z1, zs)): + seg = np.empty(3 * n) + seg[0::3], seg[1::3], seg[2::3] = a, b, np.nan + out.append(seg) + + add(x, y, z, tx, ty, tz) # the shaft + for side in (p, -p, q, -q): # the four barbs + add(tx, ty, tz, + tx - ux * barb + side[:, 0] * barb * spread, + ty - uy * barb + side[:, 1] * barb * spread, + tz - uz * barb + side[:, 2] * barb * spread) + return (np.concatenate(xs).astype(np.float32), + np.concatenate(ys).astype(np.float32), + np.concatenate(zs).astype(np.float32)) + + +def _add_arrow_slider(fig, x, y, z, ux, uy, uz, rel, base, head): + """One client-side control scaling whole arrows, head included.""" + scales = [0.5, 0.75, 1.0, 1.5, 2.0] + steps = [] + for sc in scales: + px, py, pz = _arrow_lines(x, y, z, ux, uy, uz, rel * base * sc, head) + steps.append(dict(method="restyle", label=f"{sc:g}x", + args=[{"x": [px], "y": [py], "z": [pz]}, [0]])) + fig.update_layout(sliders=[dict( + active=scales.index(1.0), steps=steps, len=0.7, x=0.15, y=0, + pad=dict(t=8, b=8), + currentvalue=dict(prefix="arrow size: ", font=dict(size=13)), + )]) + + +def _display(fig): + """Show the figure and return nothing. + + Jupyter renders only the value of a cell's LAST expression, so a plotting + call followed by a self-check would otherwise draw nothing at all. Showing + it here makes the call work wherever it sits; returning None keeps it from + being drawn a second time when it does happen to come last. + """ + fig.show() + return None -def _style_3d(fig, title, size): + +def _style_3d(fig, title, size, bottom_margin=0): fig.update_layout( title=title, width=size, height=size, - margin=dict(l=0, r=0, t=40 if title else 0, b=0), + margin=dict(l=0, r=0, t=40 if title else 0, b=bottom_margin), scene=dict( xaxis_title="x [m]", yaxis_title="y [m]", zaxis_title="z [m]", aspectmode="cube", # equal aspect: never distort a field @@ -184,14 +371,35 @@ def _style_3d(fig, title, size): # 2-D views of the z = 0 plane (matplotlib) # -------------------------------------------------------------------------- -def show_scalar_slice(X, Y, Z, F, *, title="", label="", cmap="RdYlBu_r", - levels=25, symmetric=False, percentile=99, ax=None): - """Filled contours of a scalar field in the z = 0 plane.""" +def show_scalar_slice(X, Y, Z, F, *, title="", label="", cmap=None, + levels=25, symmetric=False, percentile=99, ax=None, + colorbar=True, vmin=None, vmax=None): + """Filled contours of a scalar field in the z = 0 plane. + + ``colorbar`` is drawn whether or not the axes was supplied by the caller; + a panel in a side-by-side comparison needs its scale just as much as a + standalone figure does. ``show_field_slice`` passes ``colorbar=False`` + because it adds its own. + + Pass ``vmin``/``vmax`` to pin the colour limits. Without them the limits + come from percentiles of *this* panel, so two panels of a comparison end + up on different scales and the extremes are clipped -- give both panels + the same explicit pair whenever the point is that they match. + + ``cmap`` defaults to a diverging map when ``symmetric=True`` and a + sequential one otherwise, so a one-signed field never gets a colour scale + implying a meaningful zero crossing. + """ k = z0_index(Z) x2, y2, f2 = X[:, :, k], Y[:, :, k], np.asarray(F)[:, :, k] - hi = np.nanpercentile(np.abs(f2) if symmetric else f2, percentile) - lo = -hi if symmetric else np.nanpercentile(f2, 100 - percentile) + if cmap is None: + cmap = "RdBu_r" if symmetric else "viridis" + if vmax is None: + vmax = np.nanpercentile(np.abs(f2) if symmetric else f2, percentile) + if vmin is None: + vmin = -vmax if symmetric else np.nanpercentile(f2, 100 - percentile) + hi, lo = float(vmax), float(vmin) lv = np.linspace(lo, hi, levels) created = ax is None @@ -202,14 +410,14 @@ def show_scalar_slice(X, Y, Z, F, *, title="", label="", cmap="RdYlBu_r", ax.set_xlabel("$x$ [m]") ax.set_ylabel("$y$ [m]") ax.set_title(title) - if created: + if colorbar: ax.figure.colorbar(cf, ax=ax, label=label) return ax, cf def show_field_slice(X, Y, Z, Ax, Ay, *, background=None, title="", label="", cmap="RdBu_r", density=1.3, symmetric=True, ax=None, - percentile=98): + percentile=98, colorbar=True, vmin=None, vmax=None): """Streamlines of a vector field in the z = 0 plane, over an optional scalar background (typically the potential that generated it).""" k = z0_index(Z) @@ -220,7 +428,8 @@ def show_field_slice(X, Y, Z, Ax, Ay, *, background=None, title="", label="", cf = None if background is not None: _, cf = show_scalar_slice(X, Y, Z, background, cmap=cmap, symmetric=symmetric, - percentile=percentile, ax=ax) + percentile=percentile, ax=ax, colorbar=False, + vmin=vmin, vmax=vmax) # streamplot needs 1-D increasing axes and arrays shaped (ny, nx); our # indexing='ij' arrays are (nx, ny), hence the transposes. @@ -237,7 +446,7 @@ def show_field_slice(X, Y, Z, Ax, Ay, *, background=None, title="", label="", ax.set_xlabel("$x$ [m]") ax.set_ylabel("$y$ [m]") ax.set_title(title) - if created and cf is not None: + if colorbar and cf is not None: ax.figure.colorbar(cf, ax=ax, label=label) return ax diff --git a/book/1_gradient_divergence_curl/labs/week01-grad-div.md b/book/1_gradient_divergence_curl/labs/week01-grad-div.md index 72bb738..0c4a85e 100644 --- a/book/1_gradient_divergence_curl/labs/week01-grad-div.md +++ b/book/1_gradient_divergence_curl/labs/week01-grad-div.md @@ -14,33 +14,29 @@ mystnb: execution_mode: 'off' --- -# Gradient and Divergence +# Lab: Gradient and Divergence :::{admonition} Computer lab :class: note -A practical companion to the lecture notes on the gradient and the divergence. You build both operators yourself, in three dimensions, and then use them to recover a charge distribution from nothing but its field. +A practical companion to the lectures on the gradient and the divergence. Each task states a physical question, gives you the steps, and ends with a self-check you can run. What we supply is the *plotting*, in a module called `fwtools` — drawing a transparent isosurface teaches you nothing about electromagnetism, so your time goes on physics instead. ::: ## Learning objectives By the end of this session you should be able to: -- **Read a gradient off a picture.** Explain why $\nabla f$ is perpendicular to the level surfaces of $f$, why $\nabla r = \hat{\mathbf{a}}_R$, and why the single minus sign in $\mathbf{E} = -\nabla V$ is the step from geometry to physics. -- **Distinguish "arrows spreading apart" from divergence.** Compute $\nabla\cdot\mathbf{A}$ for fields that look like sources and are not, and justify the answer with a flux argument rather than with algebra. +- **Read a gradient off a picture.** Explain why $\nabla f$ is perpendicular to the level surfaces of $f$, and why the single minus sign in $\mathbf{E} = -\nabla V$ is the step from geometry to physics. +- **Distinguish "arrows spreading apart" from divergence.** Compute $\nabla\cdot\mathbf{A}$ for fields, and justify the answer with a flux argument rather than with algebra. - **Use Gauss's law as a measurement.** Verify $\nabla\cdot\mathbf{E} = \rho/\varepsilon_0$ pointwise, verify the divergence theorem $\oint_S\mathbf{E}\cdot d\mathbf{s} = \int_v \nabla\cdot\mathbf{E}\,dv$ numerically, and explain what happens to both when the source shrinks to a point. -## How this lab works - -**You write the code.** Each task states a physical question, gives you the steps, and ends with a self-check you can run. What we supply is the *plotting*, in a module called `fwtools` — drawing a transparent isosurface teaches you nothing about electromagnetism, so your time goes on physics instead. - -**Nine tasks.** The scaffolding thins out as the afternoon goes on: the first tasks have blanks to fill, the last ones give you an empty cell and a list of steps. After each task there is a dropdown solution — open it *after* you have tried, or when you have been stuck on syntax for more than a couple of minutes. --- ## Part 0 — Setup ```{code-cell} ipython3 +# Nothing above the K = ... line near the bottom is physics; skip to there. import sys, pathlib import numpy as np @@ -67,7 +63,7 @@ except ModuleNotFoundError: _nb.__version__ = "5.10.4" sys.modules["nbformat"] = _nb -for _p in (".", "week-01-Grad-Div", "/week-01-Grad-Div", "book/1_gradient_divergence_curl/labs"): +for _p in (".", "book/1_gradient_divergence_curl/labs"): if (pathlib.Path(_p) / "fwtools.py").exists(): sys.path.insert(0, _p) break @@ -82,31 +78,49 @@ except ModuleNotFoundError: pio.renderers.default = "plotly_mimetype+notebook" # --------------------------------------------------------------------------- -K = 1.0 / (4.0 * np.pi * epsilon_0) # Coulomb constant, 8.99e9 V*m/C +k_e = 1.0 / (4.0 * np.pi * epsilon_0) # Coulomb constant, 8.99e9 V*m/C Q = 1e-9 # 1 nC test charge print(f"epsilon_0 = {epsilon_0:.4e} F/m") -print(f"K = {K:.4e} V*m/C") +print(f"k_e = {k_e:.4e} V*m/C") ``` -:::{admonition} What that middle block is for -:class: dropdown - -Live Code runs Python inside your browser using Pyodide. Pyodide ships numpy, scipy and matplotlib but not plotly, and plotly in turn refuses to draw anything unless it can find a package called `nbformat` — which it uses only to convince itself that it is running in a notebook. The block installs both, then locates `fwtools.py`, whose position depends on whether you are in JupyterLab or in the browser's virtual filesystem. Running locally, none of those branches execute. -::: - -Everything in this lab lives on one cube of sample points. +First make a cube grid: ```{code-cell} ipython3 -X, Y, Z, dx, dy, dz = fw.make_grid_3d(n=61, L=2.0) +n, L = 61, 2.0 # odd n, so the origin is a sample point +axis = np.linspace(-L, L, n) # one axis, shared by x, y and z +X, Y, Z = np.meshgrid(axis, axis, axis, indexing="ij") +dx = dy = dz = axis[1] - axis[0] + +c = n // 2 # index of the origin +# Masks the self-checks reuse. `interior` drops the two outermost cells so +# that comparisons never include the six faces of the box, where a field is +# sampled at its worst and np.gradient has only one-sided neighbours. +interior = np.zeros(X.shape, dtype=bool) +interior[2:-2, 2:-2, 2:-2] = True print(f"grid shape {X.shape}, spacing {dx:.4f} m, {X.size:,} sample points") -print(f"domain: {X.min():.1f} m to {X.max():.1f} m on each axis") +print(f"X[i,j,k] = x[i] -> X[-1, 0, 0] = {X[-1, 0, 0]:.1f} m") ``` -:::{admonition} Grid convention — two rules for the whole afternoon +:::{admonition} Grid convention :class: tip +**Resolution.** Every derivative on this page is a centred difference, so its error falls as $\Delta x^{2}$. Measured worst-case error against the analytic answer: + +| $n$ | $\Delta x$ [m] | $\lvert\nabla R\rvert$ | $\nabla(1/R)$ | $\nabla\cdot\mathbf{E}$ | +| ---: | ---: | ---: | ---: | ---: | +| 21 | 0.200 | 4.1% | 12.5% | 9.1% | +| 41 | 0.100 | 1.8% | 3.3% | 2.4% | +| **61** | **0.067** | **0.8%** | **1.6%** | **1.1%** | +| 81 | 0.050 | 0.5% | 1.0% | 0.6% | + +Halving $\Delta x$ quarters the error, as second order requires. $n = 61$ was chosen by that measurement: it is the coarsest grid that keeps every task under 2%, and each 3-D figure it produces weighs about 1.5 MB. **If you change `n`, keep it at 41 or above** — the self-checks below allow 5%, and $n = 31$ already fails Task 3. + +Note also that the box is a finite window on fields that extend to infinity: the largest closed surface in Part 5 sits only 0.6 m inside the outer face. + + The grid is built with `indexing='ij'`, so axis 0 is $x$, axis 1 is $y$, axis 2 is $z$. 1. **Derivatives come back in coordinate order:** `np.gradient(f, dx, dy, dz)` returns $\partial f/\partial x$, $\partial f/\partial y$, $\partial f/\partial z$. No transposes. @@ -121,10 +135,12 @@ Numpy's default is `indexing='xy'`, which returns the $y$-derivative first. That Before any physics, one piece of pure geometry. The simplest scalar field there is: -$$ r(x,y,z) = \sqrt{(x-x_0)^2 + (y-y_0)^2 + (z-z_0)^2} $$ +$$ R(x,y,z) = \sqrt{(x-x_0)^2 + (y-y_0)^2 + (z-z_0)^2} $$ *How far am I from that point?* One number at every location in space. No charge, no potential, no units of anything — just distance. +This is the **spherical** radial coordinate $R$ — distance from a point. The cylindrical $r$, distance from an axis, is a different quantity, and Part 4 returns to the distinction. The equations on this page use $R$; the code calls it `r`, because it is the only radius in the lab. + ### Task 1 — build the distance field ```{code-cell} ipython3 @@ -137,7 +153,6 @@ def distance_to(X, Y, Z, x0=0.0, y0=0.0, z0=0.0): r = distance_to(___, ___, ___) # source at the origin # --- self-check (leave this alone) --- -c = X.shape[0] // 2 # index of the origin fw.check_shape("r", r, X.shape) fw.check("r = 0 at the origin", np.isclose(r[c, c, c], 0.0)) fw.check("r = 2 m at (2,0,0)", np.isclose(r[-1, c, c], 2.0)) @@ -156,20 +171,19 @@ r = distance_to(X, Y, Z) ``` ::: -A surface on which $r$ takes one fixed value is an **isosurface**, or level set — the three-dimensional version of a contour line on a map. Draw a few, with transparency, so the inner ones show through the outer ones. +A surface on which $R$ takes one fixed value is an **isosurface**, or level set — the three-dimensional version of a contour line on a map. ```{code-cell} ipython3 -fw.show_isosurfaces(X, Y, Z, r, levels=[0.5, 1.0, 1.5], +fw.show_isosurfaces(X, Y, Z, r, levels=[0.5, 1.0, 1.5], label="r [m]", title="Isosurfaces of the distance function r") ``` -**Drag the figure to rotate it.** They are nested spheres — which is only to say that "all the points 1 metre from here" *is* a sphere. Nothing deeper than that. But keep the picture in mind: in a moment the gradient will turn out to be perpendicular to these surfaces, and that will not be a coincidence. ### Task 2 — the gradient of the distance -Compute $\nabla r$. Before you run anything, predict two things and write them down: **which way** the arrows point, and **how long** they are. +Compute $\nabla R$. Before you run anything, predict two things and write them down: **which way** the arrows point, and **how long** they are. -Then test the prediction quantitatively. The outward unit radial vector is $\hat{\mathbf{a}}_R = (x\,\hat{\mathbf{a}}_x + y\,\hat{\mathbf{a}}_y + z\,\hat{\mathbf{a}}_z)/r$, so the radial part of any vector field $\mathbf{A}$ is $\mathbf{A}\cdot\hat{\mathbf{a}}_R$. If $\nabla r$ is *purely* radial, that projection recovers its full magnitude and nothing is left over. +Then test the prediction quantitatively. The outward unit radial vector is $\hat{\mathbf{a}}_R = (x\,\hat{\mathbf{a}}_x + y\,\hat{\mathbf{a}}_y + z\,\hat{\mathbf{a}}_z)/R$, so the radial part of any vector field $\mathbf{A}$ is $\mathbf{A}\cdot\hat{\mathbf{a}}_R$. If $\nabla R$ is *purely* radial, that projection recovers its full magnitude. ```{code-cell} ipython3 # The outward unit radial vector, used again later. @@ -188,12 +202,12 @@ grad_r_mag = np.sqrt(___ + ___ + ___) radial_part = grx * ___ + gry * ___ + grz * ___ -fw.show_cones(X, Y, Z, ___, ___, ___, step=8, +fw.show_cones(X, Y, Z, grx, gry, grz, step=8, label="|∇r| [-]", title="grad r -- unit vectors pointing away from the source") # --- self-check (leave this alone) --- band = (r > 0.4) & (r < 1.6) -fw.check_shape("grad r", grx, X.shape) +fw.check_shape("grad r (x-component)", grx, X.shape) fw.check_close("|grad r| = 1 everywhere", grad_r_mag, 1.0, rtol=0.05, where=band) fw.check_close("grad r is purely radial", radial_part, 1.0, rtol=0.05, where=band) ``` @@ -208,34 +222,19 @@ radial_part = grx * aRx + gry * aRy + grz * aRz print(f"|grad r| median in 0.4 < r < 1.6 m : " f"{np.median(grad_r_mag[(r > 0.4) & (r < 1.6)]):.4f}") - -fw.show_cones(X, Y, Z, grx, gry, grz, step=8, - title="grad r -- unit vectors pointing away from the source") ``` ::: :::{admonition} The magnitude is 1. Everywhere. :class: important -That is not a numerical accident. - -Walk one metre directly away from the source point and your distance from it increases by exactly one metre. The steepest possible rate of change of $r$ is therefore 1 metre per metre — a slope of 1 — no matter where you are standing. So - -$$ \nabla r = \hat{\mathbf{a}}_R $$ - -This is the cleanest illustration of what a gradient *is*: a direction of steepest increase, carrying a length equal to that rate of increase. - -The second check says something else worth having. The arrows are perpendicular to the spheres because moving *along* a sphere does not change $r$ at all — and a direction that produces no change contributes nothing to the gradient. That argument holds for every scalar field: **$\nabla f$ is always normal to the level surfaces of $f$.** -::: - -:::{admonition} A rule you will use twice more today -:class: tip +Walk one metre directly away from the source and your distance from it grows by exactly one metre. The steepest rate of change of $R$ is 1 m/m, wherever you stand: -Any field that depends on position only through $r$ — call it $g(r)$ — has level surfaces that are spheres, so its gradient must be radial. Its magnitude is just the ordinary derivative: +$$ \nabla R = \hat{\mathbf{a}}_R $$ -$$ \nabla g(r) = \frac{dg}{dr}\,\hat{\mathbf{a}}_R $$ +The second check fixes the direction: moving *along* a sphere does not change $R$, so the gradient has no component there. **$\nabla f$ is normal to the level surfaces of $f$** — for every scalar field, not just this one. -Task 2 is the case $g = r$, giving $\nabla r = 1\cdot\hat{\mathbf{a}}_R$. **Use this rule to predict the next two tasks before you run them.** +The chain rule now settles the next two tasks in advance: $\nabla g(R) = \dfrac{dg}{dR}\,\hat{\mathbf{a}}_R$ for any $g$ depending on position only through $R$. Predict before you run. ::: --- @@ -244,9 +243,9 @@ Task 2 is the case $g = r$, giving $\nabla r = 1\cdot\hat{\mathbf{a}}_R$. **Use Now the function the physics actually uses: not the distance, but **one over** the distance, -$$ f(r) = \frac{1}{r}, \qquad\text{so}\qquad \nabla f = \frac{d}{dr}\!\left(\frac{1}{r}\right)\hat{\mathbf{a}}_R = -\frac{1}{r^{2}}\,\hat{\mathbf{a}}_R $$ +$$ f(R) = \frac{1}{R}, \qquad\text{so}\qquad \nabla f = \frac{d}{dR}\!\left(\frac{1}{R}\right)\hat{\mathbf{a}}_R = -\frac{1}{R^{2}}\,\hat{\mathbf{a}}_R $$ -Same spheres as isosurfaces — $f$ is constant wherever $r$ is constant. But the *ordering* has been turned inside out: $f$ is now largest near the source and decays to nothing far away. Predict what that does to the arrows, then check the prediction against the formula above, then measure it. +Same spheres as isosurfaces — $f$ is constant wherever $R$ is constant. But the *ordering* has been turned inside out: $f$ is now largest near the source and decays to nothing far away. Predict what that does to the arrows, then check the prediction against the formula above, then measure it. ### Task 3 — the gradient of the inverse distance @@ -257,19 +256,22 @@ r_masked = np.where(r < 0.25, np.nan, r) f = 1.0 / r_masked # Task 3 -# 1. grad f, as components fx, fy, fz; then its magnitude f_mag. -# 2. Print f_mag against the predicted 1/r^2 at r = 0.6, 1.0 and 1.5 m. -# 3. Draw it with normalise=True (direction only -- the magnitude spans -# three orders of magnitude across this box and would swamp the picture). +# 1. grad f, as components fx, fy, fz; then its magnitude f_mag. The +# self-check compares it against the predicted 1/R^2. +# 2. Draw it with normalise=True: every arrow the same length, so the +# picture shows direction only. The magnitude is not lost -- it moves +# into the colour, on a log scale (it spans three decades here). Pass +# a label so the colorbar names the quantity, e.g. +# label="|∇(1/R)| [m-2]" -- plotly colorbars take +# Unicode and a little HTML, not LaTeX. -# Write your code here: +fx, fy, fz = ___ +f_mag = ___ # --- self-check (leave this alone) --- -interior = np.zeros_like(r, dtype=bool) -interior[2:-2, 2:-2, 2:-2] = True # np.gradient is one-sided at the edges -outside = (r > 0.5) & interior +outside = (r > 0.5) & interior # `interior` was built in Part 0 fw.check_close("|grad(1/r)| = 1/r^2", f_mag, 1.0 / r_masked**2, rtol=0.05, where=outside) fw.check("grad(1/r) points inward at (1,0,0)", fx[-1 - 15, c, c] < 0) ``` @@ -286,6 +288,7 @@ for rr in (0.6, 1.0, 1.5): print(f"r = {rr:.1f} m : |grad f| = {f_mag[i, c, c]:8.4f} 1/r^2 = {1/rr**2:8.4f}") fw.show_cones(X, Y, Z, fx, fy, fz, step=8, normalise=True, + label="|∇(1/r)| [m-2]", title="grad(1/r) -- pointing back towards the source") ``` ::: @@ -295,18 +298,18 @@ fw.show_cones(X, Y, Z, fx, fy, fz, step=8, normalise=True, The arrows have reversed. Same spheres, same source, opposite direction: -$$ \nabla r = +\hat{\mathbf{a}}_R, \qquad\qquad \nabla\!\left(\frac{1}{r}\right) = -\frac{1}{r^{2}}\,\hat{\mathbf{a}}_R $$ +$$ \nabla R = +\hat{\mathbf{a}}_R, \qquad\qquad \nabla\!\left(\frac{1}{R}\right) = -\frac{1}{R^{2}}\,\hat{\mathbf{a}}_R $$ -Nothing about space changed. What changed is **which way the function climbs**. And the steepness changed too: $1/r$ climbs ever faster as you approach the source, so its gradient grows as $1/r^2$ rather than staying at 1. +Nothing about space changed. What changed is **which way the function climbs**. And the steepness changed too: $1/R$ climbs ever faster as you approach the source, so its gradient grows as $1/R^2$ rather than staying at 1. A gradient knows nothing about sources, sinks, charges or fields. It only knows uphill. ::: ### Task 4 — from geometry to physics -Here the physics enters, and it enters as a single minus sign. The electric potential of a point charge $q$ is the inverse-distance function with a constant in front, +Here the physics enters, and it enters as a single minus sign. The electric potential of a point charge $Q$ is the inverse-distance function with a constant in front, -$$ V(r) = \frac{1}{4\pi\varepsilon_0}\frac{q}{r}\quad[\text{V}], $$ +$$ V(R) = \frac{1}{4\pi\varepsilon_0}\frac{Q}{R}\quad[\text{V}], $$ and the electric field is *defined* as @@ -315,19 +318,20 @@ $$ \mathbf{E} = -\nabla V \quad[\text{V/m}]. $$ You already know what $\nabla V$ does: it points inward, uphill towards the charge. The minus sign turns it round, so **the field points downhill** — which is exactly the way a positive test charge released from rest would move, losing potential energy as it goes. ```{code-cell} ipython3 -V = K * Q / r_masked +V = k_e * Q / r_masked # Task 4 # 1. E = -grad V, as components Ex, Ey, Ez; then E_mag. -# 2. Compare E_mag against the analytic K*Q/r^2 at a few radii, in V/m. -# 3. Draw it with normalise=True and confirm it points OUTWARD for q > 0. +# 2. Compare E_mag against the analytic k_e*Q/R^2 at a few radii, in V/m. +# 3. Draw it with normalise=True and confirm it points OUTWARD for Q > 0. -# Write your code here: +Ex, Ey, Ez = ___ +E_mag = ___ # --- self-check (leave this alone) --- -fw.check_close("|E| = q/(4 pi eps0 r^2)", E_mag, K * Q / r_masked**2, +fw.check_close("|E| = Q/(4 pi eps0 R^2)", E_mag, k_e * Q / r_masked**2, rtol=0.05, where=outside) fw.check("E points outward at (1,0,0)", Ex[-1 - 15, c, c] > 0) ``` @@ -343,9 +347,10 @@ E_mag = np.sqrt(Ex**2 + Ey**2 + Ez**2) for rr in (0.6, 1.0, 1.5): i = int(np.argmin(np.abs(X[:, 0, 0] - rr))) print(f"r = {rr:.1f} m : |E| = {E_mag[i, c, c]:8.3f} V/m " - f"analytic = {K*Q/rr**2:8.3f} V/m") + f"analytic = {k_e*Q/rr**2:8.3f} V/m") fw.show_cones(X, Y, Z, Ex, Ey, Ez, step=8, normalise=True, + label="|E| [V/m]", title="E = -grad V for a positive point charge") ``` ::: @@ -364,7 +369,7 @@ Part 3 is the first payoff, and it is the reason the potential is worth defining One charge is symmetric enough to be boring. Put down two: -$$ V_{\text{total}} = \frac{1}{4\pi\varepsilon_0}\left(\frac{q_1}{r_1} + \frac{q_2}{r_2}\right) $$ +$$ V_{\text{total}} = \frac{1}{4\pi\varepsilon_0}\left(\frac{Q_1}{R_1} + \frac{Q_2}{R_2}\right) $$ **Superposition** for the potential is nothing more than adding two numbers at every point, because $V$ is a scalar. Adding the two *fields* instead would mean a vector sum at every point in the cube. @@ -373,22 +378,26 @@ Since $\nabla$ is a linear operator, $-\nabla(V_1 + V_2) = \mathbf{E}_1 + \mathb ### Task 5 — build a dipole ```{code-cell} ipython3 -# Distances to two sources placed on the x-axis, both masked as before. -r_plus = np.where(distance_to(X, Y, Z, -0.5, 0.0, 0.0) < 0.25, np.nan, +# Distances to two sources on the x-axis. The guard only trips if a grid +# point lands exactly on a charge; at n = 61 none does, so nothing is masked +# here and you see the full field. Raise it if you change the grid. +r_plus = np.where(distance_to(X, Y, Z, -0.5, 0.0, 0.0) < 0.01, np.nan, distance_to(X, Y, Z, -0.5, 0.0, 0.0)) -r_minus = np.where(distance_to(X, Y, Z, +0.5, 0.0, 0.0) < 0.25, np.nan, +r_minus = np.where(distance_to(X, Y, Z, +0.5, 0.0, 0.0) < 0.01, np.nan, distance_to(X, Y, Z, +0.5, 0.0, 0.0)) # Task 5 # 1. Superpose the potentials of +Q at (-0.5, 0, 0) and -Q at (+0.5, 0, 0) # into V_dip. Scalar addition -- just a sum. # 2. Take ONE gradient, negate it: Ex_d, Ey_d, Ez_d. -# 3. Draw the z = 0 plane, potential as colour and field as streamlines: +# 3. Draw the z = 0 plane, potential as colour and field as streamlines +# (replace ... with a title of your own): # fw.show_field_slice(X, Y, Z, Ex_d, Ey_d, background=V_dip, # title=..., label="$V$ [V]") # then plt.show(). -# Write your code here: +V_dip = ___ +Ex_d, Ey_d, Ez_d = ___ @@ -404,7 +413,7 @@ fw.check("E on the mid-plane points from + to -", np.nanmean(Ex_d[mid]) > 0) :class: dropdown ```python -V_dip = K * Q / r_plus + K * (-Q) / r_minus +V_dip = k_e * Q / r_plus + k_e * (-Q) / r_minus dVx, dVy, dVz = np.gradient(V_dip, dx, dy, dz) Ex_d, Ey_d, Ez_d = -dVx, -dVy, -dVz @@ -429,7 +438,7 @@ The same object in three dimensions — positive and negative equipotential surf ```{code-cell} ipython3 lobe = np.nanpercentile(np.abs(V_dip), 97) fw.show_isosurfaces(X, Y, Z, np.nan_to_num(V_dip), levels=[-lobe, -lobe/3, lobe/3, lobe], - colorscale="RdBu", opacity=0.3, + colorscale="RdBu", opacity=0.3, label="V [V]", title="Equipotential surfaces of a dipole") ``` @@ -441,7 +450,7 @@ The gradient took a scalar and returned a vector. The divergence goes the other $$ \nabla\cdot\mathbf{A} \;=\; \lim_{\Delta v \to 0}\frac{1}{\Delta v}\oint_S \mathbf{A}\cdot d\mathbf{s} \;=\; \frac{\partial A_x}{\partial x} + \frac{\partial A_y}{\partial y} + \frac{\partial A_z}{\partial z} $$ -Read the definition on the left, not the formula on the right. **Think of $\mathbf{A}$ as the velocity of a fluid.** Draw a small box anywhere. Measure how much fluid flows out through its walls, subtract how much flows in, divide by the volume of the box, and shrink the box. That number is the divergence: +Read the definition on the left, not the formula on the right: **treat $\mathbf{A}$ as the velocity of a fluid**, put a small box anywhere, and measure the net outflow through its walls per unit volume. | $\nabla\cdot\mathbf{A}$ | Name | Picture | | :---: | :--- | :--- | @@ -454,9 +463,10 @@ Read the definition on the left, not the formula on the right. **Think of $\math ```{code-cell} ipython3 # Task 6 # Write divergence(Ax, Ay, Az, dx, dy, dz) returning -# dAx/dx + dAy/dy + dAz/dz. You need one component from each of three -# separate gradient calls -- the x-derivative of Ax, the y-derivative of -# Ay, the z-derivative of Az. The cross terms are not part of a divergence. +# dAx/dx + dAy/dy + dAz/dz -- one derivative along one axis per component. +# np.gradient(Ax, dx, axis=0) gives dAx/dx and nothing else; asking it for +# all three and throwing two away costs three times the memory, which +# matters in the browser. The cross terms are not part of a divergence. # Write your code here: @@ -474,10 +484,9 @@ fw.check_close("div of the position vector = 3", ```python def divergence(Ax, Ay, Az, dx, dy, dz): - dAx_dx = np.gradient(Ax, dx, dy, dz)[0] - dAy_dy = np.gradient(Ay, dx, dy, dz)[1] - dAz_dz = np.gradient(Az, dx, dy, dz)[2] - return dAx_dx + dAy_dy + dAz_dz + return (np.gradient(Ax, dx, axis=0) + + np.gradient(Ay, dy, axis=1) + + np.gradient(Az, dz, axis=2)) ``` ::: @@ -491,12 +500,27 @@ Three velocity fields. For each: **sketch it in your head, predict the sign of t | **(b)** | $-y\,\hat{\mathbf{a}}_x + x\,\hat{\mathbf{a}}_y$ | fluid rotating about the $z$-axis | | **(c)** | $x\,\hat{\mathbf{a}}_x - y\,\hat{\mathbf{a}}_y$ | stretching along $x$, squeezing along $y$ | +```{code-cell} ipython3 +# Commit to your predictions BEFORE the next cell: +1 for a source, -1 for a +# sink, 0 for solenoidal. The next cell scores them. +predictions = {"a": ___, "b": ___, "c": ___} +``` + ```{code-cell} ipython3 # Task 7 # 1. Build the three fields as triples of arrays. -# 2. Take the divergence of each with your Task 6 function; print the mean. -# 3. Draw field (c) in the z = 0 plane with fw.show_field_slice(...) and -# look hard at it before reading the note below. +# 2. Take the divergence of each with your Task 6 function, as div_a, +# div_b and div_c -- the self-check needs those names. Print the mean +# of each. +# 3. Draw fields (a) and (c) side by side in the z = 0 plane, streamlines +# over their own divergence as the background, both on the SAME scale +# so the colours are comparable: +# fig, axes = plt.subplots(1, 2, figsize=(12, 4.6)) +# fw.show_field_slice(X, Y, Z, *Aa[:2], background=div_a, ax=axes[0], +# vmin=-3, vmax=3, label=r"$\nabla\cdot\mathbf{A}$", +# title="(a) outward flow") +# ... and the same for (c) with Ac and div_c. +# Look hard at the two before reading the note below. # Write your code here: @@ -506,6 +530,11 @@ Three velocity fields. For each: **sketch it in your head, predict the sign of t fw.check_close("(a) div = 3", div_a, 3.0, rtol=1e-6) fw.check_close("(b) div = 0 (rotation)", div_b + 1.0, 1.0, rtol=1e-6) fw.check_close("(c) div = 0 (shear)", div_c + 1.0, 1.0, rtol=1e-6) + +for key, measured in (("a", div_a), ("b", div_b), ("c", div_c)): + sign = int(np.sign(np.round(measured.mean(), 6))) + verdict = "as predicted" if predictions[key] == sign else "NOT what you predicted" + print(f" ({key}) you said {predictions[key]:+d}, measured {sign:+d} -- {verdict}") ``` :::{admonition} Solution — Task 7 @@ -525,7 +554,13 @@ div_c = divergence(*Ac, dx, dy, dz) for name, d in [("(a) outward flow", div_a), ("(b) rotation", div_b), ("(c) shear", div_c)]: print(f"{name:20s} div = {d.mean():+.3f}") -fw.show_field_slice(X, Y, Z, *Ac[:2], title="(c) shear flow: divergence zero", density=1.1) +fig, axes = plt.subplots(1, 2, figsize=(12, 4.6)) +for ax_, (name, A, d) in zip(axes, [("(a) outward flow", Aa, div_a), + ("(c) shear flow", Ac, div_c)]): + fw.show_field_slice(X, Y, Z, *A[:2], background=d, ax=ax_, density=1.1, + vmin=-3, vmax=3, colorbar=(ax_ is axes[-1]), + label=r"$\nabla\cdot\mathbf{A}$ [s$^{-1}$]", title=name) +plt.tight_layout() plt.show() ``` ::: @@ -533,13 +568,13 @@ plt.show() :::{admonition} Field (c) is the one that costs marks :class: warning -Along the $x$-axis, field (c) rushes *outward*, away from the origin. It looks like a source. It is not: +Along the $x$-axis, field (c) rushes outward. It looks like a source. It is not: $$ \nabla\cdot\mathbf{A} = \frac{\partial}{\partial x}(x) + \frac{\partial}{\partial y}(-y) = 1 - 1 = 0 $$ -Put a small box at the origin. Fluid pours out through the left and right walls — and pours in through the top and bottom at exactly the same rate. The parcel of fluid is stretched into a different **shape**, but its **volume** never changes. Nothing is created. +Put a box at the origin: fluid pours out through the left and right walls and in through the top and bottom at exactly the same rate. The parcel changes **shape**, never **volume**. -*Arrows pointing apart* is not the same as *divergence*. Divergence is net flux through a closed surface, and outflow in one direction can be cancelled exactly by inflow in another. Field (b) is the easy version of this idea; field (c) is the one that catches people. +*Arrows pointing apart* is not divergence. Outflow in one direction can be cancelled exactly by inflow in another — and in Task 9 you will put a closed surface around this field and measure that cancellation, rather than take it on the strength of this paragraph. ::: ### Task 8 — the divergence as a charge detector @@ -552,12 +587,18 @@ which is a strong claim: **the divergence of $\mathbf{E}$ at a point tells you t Test that pointwise on a real source. Not a point charge — that is an idealisation with infinite density at one location, and no grid can hold it. Take instead a charge **smeared over a finite blob**, which is what any actual charged object is: -$$ \rho(R) = \rho_0\,e^{-R^{2}/a^{2}}, \qquad a = 0.5\ \text{m} $$ +$$ \rho(R) = \rho_0\,e^{-R^{2}/a^{2}}, \qquad \rho_0 = 10^{-9}\ \text{C/m}^3, \qquad a = 0.5\ \text{m} $$ + +Integrating that over a sphere of radius $R$ gives the charge it encloses (bookwork — you do not need to do the integral now): -Applying Gauss's law to a sphere of radius $R$ gives the field directly (bookwork — you do not need to do this integral now): +$$ Q_{\text{enc}}(R) = \int_0^{R}\!\rho\,4\pi R'^{2}\,dR' = 4\pi\rho_0\left[\frac{a^{3}\sqrt{\pi}}{4}\operatorname{erf}\!\left(\frac{R}{a}\right) - \frac{a^{2}R}{2}e^{-R^{2}/a^{2}}\right] $$ + +and Gauss's law in the form you already know, $E_R = Q_{\text{enc}}/4\pi\varepsilon_0R^{2}$, then gives the field — the $4\pi$ cancelling: $$ E_R(R) = \frac{\rho_0}{\varepsilon_0 R^{2}}\left[\frac{a^{3}\sqrt{\pi}}{4}\operatorname{erf}\!\left(\frac{R}{a}\right) - \frac{a^{2}R}{2}e^{-R^{2}/a^{2}}\right] $$ +Check it at small $R$ before trusting it. There $Q_{\text{enc}} \to \frac{4}{3}\pi R^{3}\rho_0$, so $E_R \to \rho_0R/3\varepsilon_0$: the field **rises linearly** from zero at the centre, because the charge enclosed grows faster than the $R^{2}$ of the surface. It peaks near $R \approx a$ and only then falls off. + ```{code-cell} ipython3 from scipy.special import erf @@ -565,14 +606,22 @@ a, rho0 = 0.5, 1e-9 # Task 8 # 1. rho = rho0 * exp(-r^2 / a^2) on the grid. -# 2. E_R from the formula above, using Rs in the denominators. +# 2. E_R from the formula above, using Rs in the denominators. (The two +# bracketed terms very nearly cancel for R << a, so the closed form +# loses accuracy below R ~ 1e-6 m; on this grid the only such sample +# is the origin, where the a_R components are zero anyway.) # 3. Turn the radial magnitude into components along a_R: # Ex_b = E_R * aRx, and likewise for y and z. # 4. div_blob = divergence(...), and compare it against rho / epsilon_0 # everywhere -- including inside the source. -# 5. Plot both, side by side, in the z = 0 plane: -# fig, axes = plt.subplots(1, 2, figsize=(11, 4.4)) -# fw.show_scalar_slice(..., ax=axes[0], cmap="magma", title=...) +# 5. Plot both, side by side, in the z = 0 plane. Pass the SAME vmin and +# vmax to each panel, or they get separate auto-scales and the two +# pictures are no longer comparable -- which is the whole point: +# hi = float(np.nanmax(rho / epsilon_0)) +# fig, axes = plt.subplots(1, 2, figsize=(12, 4.4)) +# fw.show_scalar_slice(X, Y, Z, div_blob, ax=axes[0], cmap="magma", +# vmin=0, vmax=hi, label=..., title=...) +# fw.show_scalar_slice(X, Y, Z, rho / epsilon_0, ax=axes[1], ...) # Write your code here: @@ -580,9 +629,10 @@ a, rho0 = 0.5, 1e-9 # --- self-check (leave this alone) --- peak = np.nanmax(rho / epsilon_0) -err = np.nanmax(np.abs(div_blob[interior] - (rho / epsilon_0)[interior])) / peak -fw.check(f"div E = rho/eps0 pointwise (worst {err:.2%} of peak)", err < 0.05, - "check the component construction Ex_b = E_R * aRx") +_e = np.abs(div_blob[interior] - (rho / epsilon_0)[interior]) / peak +cart_worst, cart_median = float(_e.max()), float(np.median(_e)) +fw.check(f"div E = rho/eps0 pointwise (worst {cart_worst:.2%} of peak)", + cart_worst < 0.05, "check the component construction Ex_b = E_R * aRx") ``` :::{admonition} Solution — Task 8 @@ -598,11 +648,14 @@ Ex_b, Ey_b, Ez_b = E_R * aRx, E_R * aRy, E_R * aRz div_blob = divergence(Ex_b, Ey_b, Ez_b, dx, dy, dz) -fig, axes = plt.subplots(1, 2, figsize=(11, 4.4)) -fw.show_scalar_slice(X, Y, Z, div_blob, ax=axes[0], cmap="magma", - title=r"measured $\nabla\cdot\mathbf{E}$") -fw.show_scalar_slice(X, Y, Z, rho / epsilon_0, ax=axes[1], cmap="magma", - title=r"actual $\rho/\varepsilon_0$") +hi = float(np.nanmax(rho / epsilon_0)) +units = r"[V m$^{-2}$]" +fig, axes = plt.subplots(1, 2, figsize=(12, 4.4)) +fw.show_scalar_slice(X, Y, Z, div_blob, ax=axes[0], cmap="magma", label=units, + vmin=0, vmax=hi, title=r"measured $\nabla\cdot\mathbf{E}$") +fw.show_scalar_slice(X, Y, Z, rho / epsilon_0, ax=axes[1], cmap="magma", label=units, + vmin=0, vmax=hi, title=r"actual $\rho/\varepsilon_0$") +plt.tight_layout() plt.show() print(f"peak of rho/eps0 : {np.nanmax(rho/epsilon_0):8.2f}") @@ -613,24 +666,70 @@ print(f"peak of measured div: {np.nanmax(div_blob):8.2f}") :::{admonition} What you just did :class: important -The two pictures are the same picture. You never told the code where the charge was — you handed it a *field*, differentiated it, and the charge distribution came back out. That is Gauss's law working as an instrument rather than a formula. +The two pictures are the same picture. You never told the code where the charge was — you handed it a *field*, differentiated it, and the charge distribution came back out. + +Notice where the divergence vanishes: everywhere outside the blob, where the field is still large and still spreading. **Strong field, zero divergence** — the two ideas are unrelated. +::: + +### The same operator, a different formula + +Everything so far used the Cartesian formula, because `np.gradient` differentiates along array axes. But the divergence *is* flux per unit volume — a physical quantity, which cannot depend on the axes you happened to choose. Only the formula changes: + +| | Gradient $\nabla T$ | Divergence $\nabla\cdot\mathbf{A}$ | +| :--- | :--- | :--- | +| Cartesian $(x,y,z)$ | $\dfrac{\partial T}{\partial x}\hat{\mathbf{a}}_x + \dfrac{\partial T}{\partial y}\hat{\mathbf{a}}_y + \dfrac{\partial T}{\partial z}\hat{\mathbf{a}}_z$ | $\dfrac{\partial A_x}{\partial x} + \dfrac{\partial A_y}{\partial y} + \dfrac{\partial A_z}{\partial z}$ | +| Cylindrical $(r,\phi,z)$ | $\dfrac{\partial T}{\partial r}\hat{\mathbf{a}}_r + \dfrac{1}{r}\dfrac{\partial T}{\partial \phi}\hat{\mathbf{a}}_\phi + \dfrac{\partial T}{\partial z}\hat{\mathbf{a}}_z$ | $\dfrac{1}{r}\dfrac{\partial (rA_r)}{\partial r} + \dfrac{1}{r}\dfrac{\partial A_\phi}{\partial \phi} + \dfrac{\partial A_z}{\partial z}$ | +| Spherical $(R,\theta,\phi)$ | $\dfrac{\partial T}{\partial R}\hat{\mathbf{a}}_R + \dfrac{1}{R}\dfrac{\partial T}{\partial \theta}\hat{\mathbf{a}}_\theta + \dfrac{1}{R\sin\theta}\dfrac{\partial T}{\partial \phi}\hat{\mathbf{a}}_\phi$ | $\dfrac{1}{R^{2}}\dfrac{\partial (R^{2}A_R)}{\partial R} + \dfrac{1}{R\sin\theta}\dfrac{\partial (A_\theta \sin\theta)}{\partial \theta} + \dfrac{1}{R\sin\theta}\dfrac{\partial A_\phi}{\partial \phi}$ | + +Cylindrical $r$ is the distance from the $z$-axis; spherical $R$, used throughout this lab, is the distance from the origin. + +Both fields you have built are spherically symmetric — $\mathbf{E} = E_R(R)\,\hat{\mathbf{a}}_R$, with no $\theta$ or $\phi$ dependence — so two of the three spherical terms vanish and the divergence collapses to one ordinary derivative along one line: + +$$ \nabla\cdot\mathbf{E} \;=\; \frac{1}{R^{2}}\frac{d}{dR}\!\left(R^{2}E_R\right) $$ + +```{code-cell} ipython3 +dR = 0.005 +R_line = np.arange(0.05, 2.0 + dR, dR) # one radial line, not a cube + +# the same two fields as before, as functions of R alone +E_R_blob = rho0 / (epsilon_0 * R_line**2) * ( + (a**3 * np.sqrt(np.pi) / 4) * erf(R_line / a) + - (a**2 * R_line / 2) * np.exp(-R_line**2 / a**2)) +E_R_point = k_e * Q / R_line**2 + +div_blob_sph = np.gradient(R_line**2 * E_R_blob, dR) / R_line**2 +div_point_sph = np.gradient(R_line**2 * E_R_point, dR) / R_line**2 + +rho_line = rho0 * np.exp(-R_line**2 / a**2) +err_sph = np.abs(div_blob_sph - rho_line / epsilon_0)[1:-1] / np.max(rho_line / epsilon_0) +print(f"blob : {R_line.size} samples on a line vs {X.size:,} in the cube") +print(f" worst error {err_sph.max():.3%} of peak, median {np.median(err_sph):.4%}") +print(f" Cartesian, from Task 8: {cart_worst:.3%} and {cart_median:.4%}") +print(f"point: R^2 E_R varies by {np.ptp(R_line**2 * E_R_point):.1e} over the whole line") +print(f" max |div E| = {np.abs(div_point_sph).max():.1e}") +``` + +:::{admonition} Why anyone bothers with curvilinear coordinates +:class: important + +Same field, same operator, same answer — from a few hundred samples on a line instead of a quarter of a million in a cube, and several times more accurately. + +For the point charge the gain is not accuracy but certainty. $R^{2}E_R = q/4\pi\varepsilon_0$ is a **constant**, so its derivative is exactly zero for every $R>0$ — not "1.35% of something", but zero. Cartesian coordinates could only ever report that the divergence was small. -Notice also where the divergence is zero: everywhere outside the blob, where the field is still large and still spreading vigorously. **Strong field, zero divergence.** The two ideas are unrelated. +Match your coordinates to the symmetry of the source and three noisy numerical derivatives collapse into one line of algebra. That is what the second and third rows of the table are for. ::: --- ## Part 5 — Flux, and the divergence theorem -Part 4 used the *differential* form of Gauss's law, which is local: it compares two numbers at the same point. The *integral* form is global, and connects a volume to the surface that encloses it: +Part 4 used the *differential* form of Gauss's law, which compares two numbers at one point. The *integral* form connects a volume to the surface enclosing it: $$ \oint_S \mathbf{E}\cdot d\mathbf{s} \;=\; \int_v \nabla\cdot\mathbf{E}\;dv \;=\; \frac{Q_{\text{enc}}}{\varepsilon_0} $$ -The first equality is the **divergence theorem**, and it is pure vector calculus — true for any well-behaved vector field, charge or no charge. The second is the physics. Together they say something remarkable: measuring $\mathbf{E}$ on a closed surface tells you how much charge is inside, and *nothing whatever* about how that charge is arranged, or about any charge outside. +The first equality is the **divergence theorem** — pure vector calculus, true for any well-behaved field. The second is the physics. Together: measuring $\mathbf{E}$ on a closed surface tells you how much charge is inside, and nothing about how it is arranged, or about any charge outside. -You will now evaluate all three quantities independently and see them agree. - -Take $S$ to be a cube of half-width $h$ centred on the origin, with faces on grid planes. On the $+x$ face the outward normal is $+\hat{\mathbf{a}}_x$, so that face contributes $\int\!\!\int E_x\,dy\,dz$; on the $-x$ face the normal is $-\hat{\mathbf{a}}_x$ and the same integral enters with a minus sign. Six faces, three pairs. +Take $S$ to be a cube of half-width $h$ centred on the origin, faces on grid planes. On the $+x$ face the outward normal is $+\hat{\mathbf{a}}_x$, so it contributes $\int\!\!\int E_x\,dy\,dz$; on the $-x$ face the normal is $-\hat{\mathbf{a}}_x$ and the same integral enters negatively. Six faces, three pairs. ### Task 9 — close the surface @@ -639,18 +738,40 @@ Take $S$ to be a cube of half-width $h$ centred on the origin, with faces on gri # spans; `fw.volume_integral(F3, dx, dy, dz)` does the same over a box. # `fw.box_indices(X, h)` gives the index range of the cube |x|,|y|,|z| <= h. # +# The x pair is written for you; the pattern is one row per axis: +# +# face pair outward samples inward samples spacings +# x Ax[i1, s, s] Ax[i0, s, s] dy, dz +# y Ay[s, i1, s] Ay[s, i0, s] dx, dz +# z Az[s, s, i1] Az[s, s, i0] dx, dy +# +# The axis you pin to i0/i1 is the axis whose spacing you leave out. +# NOTE: this closes over X, dx, dy, dz from the cell above -- it is tied to +# this grid, not a general-purpose function. + +def closed_box_flux(Ax, Ay, Az, half_width): + """Net outward flux through the cube |x|,|y|,|z| <= half_width.""" + i0, i1 = fw.box_indices(X, half_width) + s = slice(i0, i1 + 1) + flux_x = (fw.area_integral(Ax[i1, s, s], dy, dz) + - fw.area_integral(Ax[i0, s, s], dy, dz)) + flux_y = ___ + flux_z = ___ + return flux_x + flux_y + flux_z + + # Task 9 (using the blob field Ex_b, Ey_b, Ez_b from Task 8) -# 1. For h = 0.6, 1.0 and 1.4 m, get i0, i1 = fw.box_indices(X, h) and -# s = slice(i0, i1 + 1). -# 2. Surface integral. The +x face is Ex_b[i1, s, s] and the -x face is -# Ex_b[i0, s, s]; their contribution is the difference of the two area -# integrals, with dy and dz as the spacings. Add the y and z pairs. -# Wrap this in a function closed_box_flux(Ax, Ay, Az, half_width) -- -# the next section reuses it on a different field. -# 3. Volume integral of div_blob over the same cube: div_blob[s, s, s]. -# 4. Enclosed charge: volume integral of rho over the same cube, then -# divide by epsilon_0. -# 5. Print all three, in V*m, for each h. They should agree. +# 1. Finish closed_box_flux above. +# 2. For h = 0.6, 1.0 and 1.4 m, print three numbers in V*m and check they +# agree: the surface integral; the volume integral of div_blob over the +# same cube (fw.volume_integral(div_blob[s, s, s], dx, dy, dz), with +# i0, i1 = fw.box_indices(X, h)); and the enclosed charge, the volume +# integral of rho over that cube divided by epsilon_0. +# 3. Keep the h = 1.0 m surface integral as `flux_1m` -- the self-check +# below needs that exact name. +# 4. Now settle Task 7 by measurement rather than by argument: print +# closed_box_flux for fields (b) and (c). Both look like they are +# throwing fluid outwards somewhere; a closed surface is the arbiter. # Write your code here: @@ -671,16 +792,14 @@ fw.check_scalar("divergence theorem: surface = volume", flux_1m, :class: dropdown ```python -def closed_box_flux(Ax, Ay, Az, half_width): - """Net outward flux of a vector field through a cube of half-width h.""" - i0, i1 = fw.box_indices(X, half_width) - s = slice(i0, i1 + 1) - return ( - fw.area_integral(Ax[i1, s, s], dy, dz) - fw.area_integral(Ax[i0, s, s], dy, dz) - + fw.area_integral(Ay[s, i1, s], dx, dz) - fw.area_integral(Ay[s, i0, s], dx, dz) - + fw.area_integral(Az[s, s, i1], dx, dy) - fw.area_integral(Az[s, s, i0], dx, dy) - ) + flux_y = (fw.area_integral(Ay[s, i1, s], dx, dz) + - fw.area_integral(Ay[s, i0, s], dx, dz)) + flux_z = (fw.area_integral(Az[s, s, i1], dx, dy) + - fw.area_integral(Az[s, s, i0], dx, dy)) + return flux_x + flux_y + flux_z + +flux_1m = closed_box_flux(Ex_b, Ey_b, Ez_b, 1.0) # step 6 print(f"{'h [m]':>6} {'surface':>12} {'volume':>12} {'Q_enc/eps0':>12}") for h in (0.6, 1.0, 1.4): @@ -691,16 +810,18 @@ for h in (0.6, 1.0, 1.4): qenc = fw.volume_integral(rho[s, s, s], dx, dy, dz) / epsilon_0 print(f"{h:6.1f} {surf:12.3f} {vol:12.3f} {qenc:12.3f}") -flux_1m = closed_box_flux(Ex_b, Ey_b, Ez_b, 1.0) +zero = np.zeros_like(X) +print(f"\nflux of (b), the rotation : {closed_box_flux(-Y, X, zero, 1.0):+.2e}") +print(f"flux of (c), the shear : {closed_box_flux(X, -Y, zero, 1.0):+.2e}") ``` ::: :::{admonition} Three routes, one number :class: important -The three columns are three genuinely different calculations. The first never looks inside the box — it only samples $\mathbf{E}$ on a surface. The second never looks at the surface — it differentiates the field throughout the interior. The third never looks at the field at all — it integrates the charge you put there. They agree to a fraction of a percent. +Three genuinely different calculations. The first never looks inside the box; the second never looks at the surface; the third never looks at the field at all. They agree to a fraction of a percent. -Notice how the number grows with $h$ and then stops: once the cube contains essentially all of the Gaussian blob, enlarging it further adds surface area but no charge, and the flux settles at $Q_{\text{total}}/\varepsilon_0$. Charge outside a closed surface contributes exactly nothing to the flux through it — the extra field lines it sends in through one wall come straight out through another. +The number grows with $h$ and then stops: once the cube holds essentially all the charge, enlarging it adds surface but no charge. Charge outside a closed surface contributes exactly nothing — the field lines it sends in through one wall leave through another. ::: ### And now shrink the source to a point @@ -722,15 +843,49 @@ print(f"\n|div E| away from the origin: median {np.median(np.abs(div_point[shell :::{admonition} Where did the charge go? :class: important -Every box returns $Q/\varepsilon_0$. Yet the divergence is zero at every point you are able to measure, and the boxes have nothing in common except the origin. +Every box returns $Q/\varepsilon_0$, yet the divergence is zero everywhere you can measure — *exactly* zero, by the spherical calculation above — and the boxes share nothing but the origin. -So the entire source sits at a single point, and $\nabla\cdot\mathbf{E}$ there is not a large number — it is not a number at all. What $\rho$ has become is a **Dirac delta**: zero everywhere, infinite at one point, with a finite integral $q$. This is precisely the situation the integral form was made for, and the reason it survives where the differential form breaks down. +So the whole source sits at one point, where $\nabla\cdot\mathbf{E}$ is not a large number but no number at all: $\rho$ has become a **Dirac delta**, zero everywhere, infinite at one point, with a finite integral $Q$. The integral form survives exactly where the differential form breaks down. -One more consequence, for later in the course. Another of Maxwell's equations is +The same statement for magnetism carries no source term at all: $$ \nabla\cdot\mathbf{B} = 0 \qquad\Longleftrightarrow\qquad \oint_S \mathbf{B}\cdot d\mathbf{s} = 0 \ \ \text{for every closed } S $$ -with no source term on the right at all. Run this measurement on a magnetic field, around any surface anywhere in the universe, and you get zero — there are no magnetic monopoles. Field lines of $\mathbf{B}$ never begin and never end. +Run this measurement around any closed surface anywhere and you get zero: there are no magnetic monopoles, and field lines of $\mathbf{B}$ never begin and never end. +::: + +### Where do the 1% errors come from? + +Every derivative on this page is a centred difference, accurate to $O(\Delta x^{2})$. That is a law, not an excuse: halve the spacing and the error should fall by four. Confirm it — the whole study is one loop. + +```{code-cell} ipython3 +print(f"{'n':>4} {'dx [m]':>8} {'worst error':>12} {'ratio':>7}") +prev = None +for n_test in (21, 31, 41, 61): + ax_t = np.linspace(-L, L, n_test) + h_t = ax_t[1] - ax_t[0] + Xt, Yt, Zt = np.meshgrid(ax_t, ax_t, ax_t, indexing="ij") + rt = np.sqrt(Xt**2 + Yt**2 + Zt**2) + Rst = np.maximum(rt, 1e-12) + rho_t = rho0 * np.exp(-rt**2 / a**2) + E_Rt = rho0 / (epsilon_0 * Rst**2) * ( + (a**3 * np.sqrt(np.pi) / 4) * erf(Rst / a) + - (a**2 * Rst / 2) * np.exp(-Rst**2 / a**2)) + dv = divergence(E_Rt * Xt / Rst, E_Rt * Yt / Rst, E_Rt * Zt / Rst, h_t, h_t, h_t) + inner = np.zeros(Xt.shape, bool) + inner[2:-2, 2:-2, 2:-2] = True + e = np.nanmax(np.abs(dv[inner] - (rho_t / epsilon_0)[inner])) / np.nanmax(rho_t / epsilon_0) + ratio = "-" if prev is None else f"{prev / e:.2f}" + print(f"{n_test:>4} {h_t:>8.4f} {e:>11.2%} {ratio:>7}") + prev = e +``` + +:::{admonition} Second order, by measurement +:class: important + +Compare each ratio with the square of the spacing ratio — $1.5^2 = 2.25$ from $n=21$ to $31$, $1.33^2 = 1.78$ from $31$ to $41$, $1.5^2 = 2.25$ from $41$ to $61$. + +So the 1.06% in Task 8 is not noise to be tolerated: it is a number you can predict, and buy down if you need to. And the choice of $n = 61$ in Part 0 is now yours to audit rather than take on trust. ::: --- @@ -750,10 +905,12 @@ Electrostatics is the convenient place to *learn* this pair, not the only place | System | Potential | Field | Source equation | | :--- | :--- | :--- | :--- | -| Electrostatics | $V$ [V] | $\mathbf{E} = -\nabla V$ | $\nabla\cdot\mathbf{E} = \rho/\varepsilon_0$ | -| Gravitation | $\Phi$ [J/kg] | $\mathbf{g} = -\nabla \Phi$ | $\nabla\cdot\mathbf{g} = -4\pi G\rho_m$ | -| Heat conduction | $T$ [K] | $\mathbf{q} = -k\nabla T$ | $\nabla\cdot\mathbf{q} = 0$ (steady, no sources) | -| Groundwater flow | $h$ [m] | $\mathbf{q} = -K\nabla h$ | $\nabla\cdot\mathbf{q} = 0$ (steady, incompressible) | +| Electrostatics | $V$ [V] | $\mathbf{E} = -\nabla V$   [V/m] | $\nabla\cdot\mathbf{E} = \rho/\varepsilon_0$ | +| Gravitation | $\Phi$ [J/kg] | $\mathbf{g} = -\nabla \Phi$   [m/s$^2$] | $\nabla\cdot\mathbf{g} = -4\pi G\rho_m$ | +| Heat conduction | $T$ [K] | $\mathbf{q}_T = -k\nabla T$   [W/m$^2$] | $\nabla\cdot\mathbf{q}_T = 0$ (steady, no sources) | +| Groundwater flow | $h$ [m] | $\mathbf{q}_h = -K\nabla h$   [m/s] | $\nabla\cdot\mathbf{q}_h = 0$ (steady, incompressible) | + +with $k$ the thermal conductivity [W m$^{-1}$ K$^{-1}$] and $K$ the hydraulic conductivity [m/s]. The minus signs are all the same minus sign: heat flows from hot to cold, water flows from high head to low, a positive charge falls from high potential to low. Flow runs downhill, and the gradient points uphill. @@ -769,12 +926,22 @@ Keep `fwtools.py` to hand: the later labs in this chapter reuse the same helpers ### Homework -**Exercise A — a heat source in a room.** Replace the spherical blob with a flat rectangular heater, say $1.0 \times 0.6$ m in the $z = 0$ plane, built by superposing point sources over the rectangle exactly as you superposed two charges in Task 5. Then: +**Exercise A — a heat source in a room.** Replace the spherical blob with a flat rectangular heater, $1.0 \times 0.6$ m in the $z = 0$ plane. A steady point source of power $P$ in a medium of conductivity $k$ raises the temperature as $P/4\pi k R$ — the same $1/R$ you have worked with all afternoon — so superpose a $20 \times 12$ grid of them over the rectangle, exactly as you superposed two charges in Task 5: + +$$ T(\mathbf{r}) = \frac{P}{4\pi k}\sum_i \frac{\Delta A}{\lvert \mathbf{r} - \mathbf{r}_i \rvert}, \qquad k_{\text{air}} = 0.026\ \text{W m}^{-1}\text{K}^{-1} $$ + +with $P$ the total power (take 100 W) and $\Delta A$ the area each sample represents. Then: - Plot the isosurfaces. Close to the plate they should be rounded rectangles; far away they should become spheres. Why does the shape forget its source? - Compute the heat flux $\mathbf{q} = -k\nabla T$ — the same minus sign, the same reason. - Check that $\nabla\cdot\mathbf{q} \approx 0$ away from the heater, and that the closed-surface flux through a box containing the plate is *not* zero. State what each result means physically for a room at steady state. -**Exercise B — the $r^n$ family.** Using $\nabla g(r) = \dfrac{dg}{dr}\hat{\mathbf{a}}_R$, derive $|\nabla r| = 1$ and $|\nabla(1/r)| = 1/r^2$ on paper, then find which power $n$ in $r^{n}$ gives a field falling off as $1/r^{3}$. +**Exercise B — the $R^n$ family.** Using $\nabla g(R) = \dfrac{dg}{dR}\hat{\mathbf{a}}_R$, derive $|\nabla R| = 1$ and $|\nabla(1/R)| = 1/R^2$ on paper, then find which power $n$ in $R^{n}$ gives a field falling off as $1/R^{3}$. + +**Exercise C — why $1/R^2$, and not any other power.** Compute the flux of $\hat{\mathbf{a}}_R/R^{n}$ through spheres of two different radii. Show that it is independent of radius only for $n = 2$, and connect that to the fact that we live in three dimensions. This is the deepest reason Coulomb's law has the exponent it has. + +**Exercise D — the same argument in cylindrical coordinates.** An infinite line charge of density $\lambda$ on the $z$-axis produces + +$$ \mathbf{E} = \frac{\lambda}{2\pi\varepsilon_0 r}\,\hat{\mathbf{a}}_r $$ -**Exercise C — why $1/r^2$, and not any other power.** Compute the flux of $\hat{\mathbf{a}}_R/r^{n}$ through spheres of two different radii. Show that the flux is independent of radius only for $n = 2$, and connect that to the fact that we live in three dimensions. This is the deepest reason Coulomb's law has the exponent it has. +with $r$ now the distance from the *axis*, not the origin. Use the cylindrical divergence from the table to show $\nabla\cdot\mathbf{E} = 0$ for $r > 0$, in one line — note which power of $r$ makes $rA_r$ constant, and compare it with the $R^2E_R$ of the spherical case. Then take a cylinder of radius $r$ and length $L$ about the axis and show its flux is $\lambda L/\varepsilon_0$, independent of $r$. Why is the exponent 1 here where it was 2 before? From b7491e8cb5c3e71756176d696a17226f808daaa4 Mon Sep 17 00:00:00 2001 From: ARS183 <1028762817@qq.com> Date: Mon, 31 Aug 2026 18:18:02 +0200 Subject: [PATCH 04/17] Align the Week 1 lab with the lecture notes: series, DC resistivity, two sessions --- .../labs/fwtools.py | 67 +- .../labs/week01-grad-div.md | 913 ++++++++++++++---- 2 files changed, 772 insertions(+), 208 deletions(-) diff --git a/book/1_gradient_divergence_curl/labs/fwtools.py b/book/1_gradient_divergence_curl/labs/fwtools.py index 2b71943..93f45cd 100644 --- a/book/1_gradient_divergence_curl/labs/fwtools.py +++ b/book/1_gradient_divergence_curl/labs/fwtools.py @@ -368,13 +368,32 @@ def _style_3d(fig, title, size, bottom_margin=0): # -------------------------------------------------------------------------- -# 2-D views of the z = 0 plane (matplotlib) +# 2-D views of a coordinate plane (matplotlib) # -------------------------------------------------------------------------- +def _plane_slice(X, Y, Z, F, plane): + """Cut a 3-D field on a coordinate plane through the origin. + + ``plane="z"`` gives the z = 0 plane in (x, y); ``plane="y"`` gives the + y = 0 plane in (x, z) -- the vertical cross-section a geophysical survey + is usually drawn on. Returns the two 1-D axes, the 2-D field, and the two + axis labels. + """ + F = None if F is None else np.asarray(F) + if plane == "z": + k = z0_index(Z) + return (X[:, 0, k], Y[0, :, k], None if F is None else F[:, :, k], + "$x$ [m]", "$y$ [m]") + if plane == "y": + j = int(np.argmin(np.abs(Y[0, :, 0]))) + return (X[:, j, 0], Z[0, j, :], None if F is None else F[:, j, :], + "$x$ [m]", "$z$ [m]") + raise ValueError(f"plane must be 'z' or 'y', not {plane!r}") + def show_scalar_slice(X, Y, Z, F, *, title="", label="", cmap=None, levels=25, symmetric=False, percentile=99, ax=None, - colorbar=True, vmin=None, vmax=None): - """Filled contours of a scalar field in the z = 0 plane. + colorbar=True, vmin=None, vmax=None, plane="z"): + """Filled contours of a scalar field on a coordinate plane. ``colorbar`` is drawn whether or not the axes was supplied by the caller; a panel in a side-by-side comparison needs its scale just as much as a @@ -389,9 +408,11 @@ def show_scalar_slice(X, Y, Z, F, *, title="", label="", cmap=None, ``cmap`` defaults to a diverging map when ``symmetric=True`` and a sequential one otherwise, so a one-signed field never gets a colour scale implying a meaningful zero crossing. + + ``plane="z"`` cuts z = 0, ``plane="y"`` cuts y = 0 for a vertical section. """ - k = z0_index(Z) - x2, y2, f2 = X[:, :, k], Y[:, :, k], np.asarray(F)[:, :, k] + a1, b1, f2, alab, blab = _plane_slice(X, Y, Z, F, plane) + x2, y2 = np.meshgrid(a1, b1, indexing="ij") if cmap is None: cmap = "RdBu_r" if symmetric else "viridis" @@ -407,8 +428,8 @@ def show_scalar_slice(X, Y, Z, F, *, title="", label="", cmap=None, _, ax = plt.subplots(figsize=(5.4, 4.5)) cf = ax.contourf(x2, y2, np.clip(f2, lo, hi), levels=lv, cmap=cmap, extend="both") ax.set_aspect("equal") # course rule: never distort a field plot - ax.set_xlabel("$x$ [m]") - ax.set_ylabel("$y$ [m]") + ax.set_xlabel(alab) + ax.set_ylabel(blab) ax.set_title(title) if colorbar: ax.figure.colorbar(cf, ax=ax, label=label) @@ -417,10 +438,14 @@ def show_scalar_slice(X, Y, Z, F, *, title="", label="", cmap=None, def show_field_slice(X, Y, Z, Ax, Ay, *, background=None, title="", label="", cmap="RdBu_r", density=1.3, symmetric=True, ax=None, - percentile=98, colorbar=True, vmin=None, vmax=None): - """Streamlines of a vector field in the z = 0 plane, over an optional - scalar background (typically the potential that generated it).""" - k = z0_index(Z) + percentile=98, colorbar=True, vmin=None, vmax=None, + plane="z"): + """Streamlines of a vector field on a coordinate plane, over an optional + scalar background (typically the potential that generated it). + + ``plane="z"`` cuts z = 0 and expects the (x, y) components; ``plane="y"`` + cuts y = 0 and expects the (x, z) components -- pass ``Ax, Az`` there. + """ created = ax is None if created: _, ax = plt.subplots(figsize=(5.8, 4.8)) @@ -429,22 +454,22 @@ def show_field_slice(X, Y, Z, Ax, Ay, *, background=None, title="", label="", if background is not None: _, cf = show_scalar_slice(X, Y, Z, background, cmap=cmap, symmetric=symmetric, percentile=percentile, ax=ax, colorbar=False, - vmin=vmin, vmax=vmax) - - # streamplot needs 1-D increasing axes and arrays shaped (ny, nx); our - # indexing='ij' arrays are (nx, ny), hence the transposes. - x1 = X[:, 0, k] - y1 = Y[0, :, k] - u = np.nan_to_num(np.asarray(Ax)[:, :, k]).T - v = np.nan_to_num(np.asarray(Ay)[:, :, k]).T + vmin=vmin, vmax=vmax, plane=plane) + + # streamplot needs 1-D increasing axes and arrays shaped (nb, na); our + # indexing='ij' arrays are (na, nb), hence the transposes. + x1, y1, u2, alab, blab = _plane_slice(X, Y, Z, Ax, plane) + _, _, v2, _, _ = _plane_slice(X, Y, Z, Ay, plane) + u = np.nan_to_num(u2).T + v = np.nan_to_num(v2).T ax.streamplot(x1, y1, u, v, color="k", linewidth=0.7, density=density, arrowsize=0.9) ax.set_aspect("equal") ax.set_xlim(x1.min(), x1.max()) ax.set_ylim(y1.min(), y1.max()) - ax.set_xlabel("$x$ [m]") - ax.set_ylabel("$y$ [m]") + ax.set_xlabel(alab) + ax.set_ylabel(blab) ax.set_title(title) if colorbar and cf is not None: ax.figure.colorbar(cf, ax=ax, label=label) diff --git a/book/1_gradient_divergence_curl/labs/week01-grad-div.md b/book/1_gradient_divergence_curl/labs/week01-grad-div.md index 0c4a85e..4ae3769 100644 --- a/book/1_gradient_divergence_curl/labs/week01-grad-div.md +++ b/book/1_gradient_divergence_curl/labs/week01-grad-div.md @@ -24,17 +24,26 @@ A practical companion to the lectures on the gradient and the divergence. Each t ## Learning objectives -By the end of this session you should be able to: +By the end of this lab you should be able to: -- **Read a gradient off a picture.** Explain why $\nabla f$ is perpendicular to the level surfaces of $f$, and why the single minus sign in $\mathbf{E} = -\nabla V$ is the step from geometry to physics. -- **Distinguish "arrows spreading apart" from divergence.** Compute $\nabla\cdot\mathbf{A}$ for fields, and justify the answer with a flux argument rather than with algebra. -- **Use Gauss's law as a measurement.** Verify $\nabla\cdot\mathbf{E} = \rho/\varepsilon_0$ pointwise, verify the divergence theorem $\oint_S\mathbf{E}\cdot d\mathbf{s} = \int_v \nabla\cdot\mathbf{E}\,dv$ numerically, and explain what happens to both when the source shrinks to a point. +- **Truncate a series and know what you lost.** Sum a geometric series, approximate it by its leading term, and say how many terms buy a given accuracy — and where a Taylor series stops working altogether. +- **Read a gradient off a picture.** Show that $\nabla r = \hat{\boldsymbol{r}}$, that $\nabla f$ is perpendicular to the level surfaces of $f$, and that $dp/dl = \lvert\nabla p\rvert\cos\psi$ — so the gradient's magnitude *is* the maximum rate of change. +- **Turn a potential into a field, and a field into a survey.** Apply $\boldsymbol{E} = -\nabla V$ and Ohm's law $\boldsymbol{J} = -\rho^{-1}\nabla V$, and map the potential and current density of a two-electrode DC resistivity measurement. +- **Distinguish "arrows spreading apart" from divergence.** Compute $\nabla\cdot\boldsymbol{v}$, justify the answer by flux rather than algebra, and find the only radial flow that is incompressible. +- **Use the divergence theorem as a measurement.** Verify $\oint_S\boldsymbol{v}\cdot\hat{\boldsymbol{n}}\,dS = \int_D \nabla\cdot\boldsymbol{v}\,dV$ numerically, and explain what happens when the source shrinks to a point. +:::{admonition} Two sessions +:class: note + +**Session 1** runs to the end of Part 4, covering the gradient. **Part 5 onwards is the following session**, once the divergence has been lectured. Everything is in one page so you can work ahead if you want to. +::: --- ## Part 0 — Setup +Run this once. Nothing in it is physics: it fetches two packages the browser lacks, finds `fwtools`, and defines the Coulomb constant for later. + ```{code-cell} ipython3 # Nothing above the K = ... line near the bottom is physics; skip to there. import sys, pathlib @@ -85,7 +94,178 @@ print(f"epsilon_0 = {epsilon_0:.4e} F/m") print(f"k_e = {k_e:.4e} V*m/C") ``` -First make a cube grid: +--- + +## Part 1 — Series, and what you lose by truncating + +Before any fields, one point that runs through the whole course: a physical quantity is often an infinite sum, and we almost always keep only the first few terms. This part is about what that costs. + +### Task 1 — the bouncing ball + +A ball leaves the ground at $z=0$ with upward velocity $v_0$. Between bounces it is in free fall, + +$$ z(t) = v_0 t - \tfrac{1}{2}g t^2, $$ + +so it returns to the ground after $T_0 = 2v_0/g$ having reached a height $H = v_0^2/2g$. At each bounce it loses a fraction $\gamma$ of its energy, so $v_n = \sqrt{1-\gamma}\;v_{n-1}$, and since flight time is proportional to launch speed, + +$$ T_n = (1-\gamma)^{n/2}\,T_0, \qquad T_0 = \sqrt{8H/g}. $$ + +Fill in the three physical lines. The plotting is written for you. + +```{code-cell} ipython3 +g, v0, gamma = 9.81, 5.0, 0.1 +N = 12 # bounces to draw + +H = ___ # peak height of the first flight +T0 = ___ # duration of the first flight +T = T0 * ___ # durations of bounces 0 .. N-1 + +# --- given: draw one parabola per bounce --- +t_start = np.concatenate(([0.0], np.cumsum(T)[:-1])) +plt.figure(figsize=(9, 3.4)) +for Tn, t0 in zip(T, t_start): + tau = np.linspace(0, Tn, 200) + plt.plot(t0 + tau, (g*Tn/2)*tau - g*tau**2/2, "C0") +plt.xlabel("$t$ [s]"); plt.ylabel("$z$ [m]"); plt.grid(alpha=0.3) +plt.title(f"bouncing ball, $\\gamma$ = {gamma}") +plt.show() + +# --- self-check (leave this alone) --- +fw.check(f"H = {H:.4f} m", np.isclose(H, v0**2/(2*g)), "H = v0^2 / 2g") +fw.check(f"T0 = {T0:.4f} s", np.isclose(T0, 2*v0/g), "T0 = 2 v0 / g") +fw.check("T0 = sqrt(8H/g) too", np.isclose(T0, np.sqrt(8*H/g))) +fw.check(f"{N} bounce durations, shrinking", len(T) == N and T[-1] < T[0]) +``` + +:::{admonition} Solution — Task 1 +:class: dropdown + +```python +H = v0**2 / (2*g) +T0 = 2*v0 / g +T = T0 * (1 - gamma)**(np.arange(N)/2) +``` +::: + +Now the series. The ball bounces for a total time + +$$ T_\infty = \sum_{m=0}^{\infty} T_m = T_0\sum_{m=0}^{\infty}\left(\sqrt{1-\gamma}\right)^{m} = \frac{\sqrt{8H/g}}{1-\sqrt{1-\gamma}}, $$ + +which is a geometric series and therefore **finite** — infinitely many bounces, over in about twenty seconds. For small $\gamma$ the expansion $\sqrt{1-\gamma}\approx 1-\gamma/2$ collapses that to something much simpler, + +$$ T_\infty \approx \sqrt{8H/g}\;\frac{2}{\gamma}. $$ + +Two questions follow, and both are worth answering by measurement rather than by intuition: **how good is that approximation**, and **how many bounces must you actually add up** before the running total gets there? + +```{code-cell} ipython3 +print(f"{'gamma':>7} {'T_inf':>9} {'approx':>9} {'error':>7} {'n for 99%':>10}") +for gam in (0.5, 0.2, 0.1, 0.02): + T_inf = ___ # the exact sum, from the formula above + T_appr = ___ # the small-gamma approximation + + # --- given: how many bounces to reach 99% of T_inf --- + cum = np.cumsum(T0 * (1 - gam)**(np.arange(4000)/2)) + n99 = int(np.argmax(cum >= 0.99*T_inf)) + 1 + print(f"{gam:>7.2f} {T_inf:>8.3f}s {T_appr:>8.3f}s " + f"{abs(T_appr-T_inf)/T_inf:>6.1%} {n99:>10}") + +# --- self-check (leave this alone) --- +_exact = np.sqrt(8*H/g) / (1 - np.sqrt(1 - 0.1)) +_summed = np.sum(T0 * (1 - 0.1)**(np.arange(5000)/2)) +fw.check(f"the closed form ({_exact:.3f} s) equals the brute-force sum ({_summed:.3f} s)", + np.isclose(_exact, _summed, rtol=1e-6)) +``` + +:::{admonition} Solution — Task 1, continued +:class: dropdown + +```python + T_inf = np.sqrt(8*H/g) / (1 - np.sqrt(1 - gam)) + T_appr = np.sqrt(8*H/g) * 2 / gam +``` +::: + +:::{admonition} What the table says +:class: important + +At $\gamma = 0.5$ the leading-term approximation is 17% wrong; at $\gamma = 0.02$ it is 0.5%. "Keep only the first term" is not a statement about algebra — it is a statement about the *regime*, and it has to be earned. + +The term count runs the other way. The more nearly elastic the ball, the more bounces you must sum for the same accuracy: 14 at $\gamma = 0.5$, 456 at $\gamma = 0.02$. Cheap approximation, expensive summation — and the two get cheap and expensive at opposite ends. You will meet that trade in every numerical method this course touches. +::: + +### Task 2 — where a Taylor series stops working + +Any smooth function can be written as a Taylor series about $x=0$, + +$$ f(x) = f(0) + x f'(0) + \tfrac{1}{2}x^2 f''(0) + \cdots, $$ + +and in practice we truncate it after a few terms. Take two: + +$$ \sin x = x - \frac{x^3}{3!} + \frac{x^5}{5!} - \cdots, \qquad\qquad \frac{1}{1+x} = 1 - x + x^2 - x^3 + \cdots $$ + +Both look equally harmless. Add terms to each and watch what happens. + +```{code-cell} ipython3 +x = np.linspace(-3, 3, 600) + +# term m of each series, as a function of x +def sin_term(m, x): + return 0.0 if m % 2 == 0 else ___ # (-1)^((m-1)/2) x^m / m! [math.factorial] + +def geo_term(m, x): + return ___ # term m of 1 - x + x^2 - ... + +# --- given: exact curve plus four truncations, side by side --- +fig, axes = plt.subplots(1, 2, figsize=(11, 4)) +for ax, (name, exact, term) in zip(axes, [ + (r"$\sin x$", np.sin, sin_term), + (r"$1/(1+x)$", lambda x: 1/(1+x), geo_term)]): + ax.plot(x, exact(x), "k", lw=2, label="exact") + for M in (2, 4, 8, 16): + ax.plot(x, sum(term(m, x) for m in range(M + 1)), lw=1, label=f"M = {M}") + ax.set_ylim(-3, 3); ax.set_xlabel("$x$"); ax.set_title(name) + ax.grid(alpha=0.3); ax.legend(fontsize=8) +plt.tight_layout() +plt.show() + +# --- self-check (leave this alone) --- +_s20 = sum(sin_term(m, x) for m in range(21)) +_g_in = sum(geo_term(m, 0.5) for m in range(40)) +_g_out = sum(geo_term(m, 1.5) for m in range(40)) +fw.check("20 terms reproduce sin(x) on -3 < x < 3", np.max(np.abs(_s20 - np.sin(x))) < 1e-6) +fw.check(f"1/(1+x) converges at x = 0.5 ({_g_in:.4f} vs {1/1.5:.4f})", np.isclose(_g_in, 1/1.5)) +fw.check(f"1/(1+x) diverges at x = 1.5 (partial sum {_g_out:.2e})", abs(_g_out) > 1e3) +``` + +:::{admonition} Solution — Task 2 +:class: dropdown + +```python +import math + +def sin_term(m, x): + return 0.0 if m % 2 == 0 else (-1)**((m-1)//2) * x**m / math.factorial(m) + +def geo_term(m, x): + return (-x)**m +``` +::: + +:::{admonition} Radius of convergence +:class: important + +$\sin x$ improves everywhere as you add terms. $1/(1+x)$ improves only inside $\lvert x\rvert < 1$; outside it, each extra term makes the partial sum *worse*, without limit — at $x = 1.5$ the 40-term "approximation" is off by millions. + +The series has a **radius of convergence** of 1, fixed by the blow-up of $1/(1+x)$ at $x = -1$, and no amount of computing power moves it. Notice that the failure is invisible at $x = 0$: the function is perfectly smooth there, and the first few terms behave well. The limit is a property of the series, not of the point you expanded about. + +Keep that beside Task 1. There, more terms always helped and the only question was how many. Here, more terms are useless past a certain point. Knowing which situation you are in is the whole skill. +::: + +--- + +## Part 2 — The distance function, and what its gradient is + +Everything from here on lives on one cube of sample points. ```{code-cell} ipython3 n, L = 61, 2.0 # odd n, so the origin is a sample point @@ -109,16 +289,16 @@ print(f"X[i,j,k] = x[i] -> X[-1, 0, 0] = {X[-1, 0, 0]:.1f} m") **Resolution.** Every derivative on this page is a centred difference, so its error falls as $\Delta x^{2}$. Measured worst-case error against the analytic answer: -| $n$ | $\Delta x$ [m] | $\lvert\nabla R\rvert$ | $\nabla(1/R)$ | $\nabla\cdot\mathbf{E}$ | +| $n$ | $\Delta x$ [m] | $\lvert\nabla r\rvert$ | $\nabla(1/r)$ | $\nabla\cdot\boldsymbol{E}$ | | ---: | ---: | ---: | ---: | ---: | | 21 | 0.200 | 4.1% | 12.5% | 9.1% | | 41 | 0.100 | 1.8% | 3.3% | 2.4% | | **61** | **0.067** | **0.8%** | **1.6%** | **1.1%** | | 81 | 0.050 | 0.5% | 1.0% | 0.6% | -Halving $\Delta x$ quarters the error, as second order requires. $n = 61$ was chosen by that measurement: it is the coarsest grid that keeps every task under 2%, and each 3-D figure it produces weighs about 1.5 MB. **If you change `n`, keep it at 41 or above** — the self-checks below allow 5%, and $n = 31$ already fails Task 3. +Halving $\Delta x$ quarters the error, as second order requires. $n = 61$ was chosen by that measurement: it is the coarsest grid that keeps every task under 2%, and each 3-D figure it produces weighs about 1.5 MB. **If you change `n`, keep it at 41 or above** — the self-checks below allow 5%, and $n = 31$ already fails Task 6. -Note also that the box is a finite window on fields that extend to infinity: the largest closed surface in Part 5 sits only 0.6 m inside the outer face. +Note also that the box is a finite window on fields that extend to infinity: the largest closed surface in Part 6 sits only 0.6 m inside the outer face. The grid is built with `indexing='ij'`, so axis 0 is $x$, axis 1 is $y$, axis 2 is $z$. @@ -129,22 +309,18 @@ The grid is built with `indexing='ij'`, so axis 0 is $x$, axis 1 is $y$, axis 2 Numpy's default is `indexing='xy'`, which returns the $y$-derivative first. That one fact is the origin of a large fraction of all numerical field bugs. ::: ---- - -## Part 1 — The distance function, and what its gradient is - -Before any physics, one piece of pure geometry. The simplest scalar field there is: +Now the geometry. The simplest scalar field there is: -$$ R(x,y,z) = \sqrt{(x-x_0)^2 + (y-y_0)^2 + (z-z_0)^2} $$ +$$ r(x,y,z) = \sqrt{(x-x_0)^2 + (y-y_0)^2 + (z-z_0)^2} $$ *How far am I from that point?* One number at every location in space. No charge, no potential, no units of anything — just distance. -This is the **spherical** radial coordinate $R$ — distance from a point. The cylindrical $r$, distance from an axis, is a different quantity, and Part 4 returns to the distinction. The equations on this page use $R$; the code calls it `r`, because it is the only radius in the lab. +This is the **spherical** radial coordinate $r$ — distance from a point. The cylindrical $r$, distance from an axis, is a different quantity, and Part 4 returns to the distinction. The equations on this page use $r$; the code calls it `r`, because it is the only radius in the lab. -### Task 1 — build the distance field +### Task 3 — build the distance field ```{code-cell} ipython3 -# Task 1 -- distance from a source at (x0, y0, z0) to every point of the grid. +# Task 3 -- distance from a source at (x0, y0, z0) to every point of the grid. def distance_to(X, Y, Z, x0=0.0, y0=0.0, z0=0.0): return np.sqrt(___ + ___ + ___) @@ -159,7 +335,7 @@ fw.check("r = 2 m at (2,0,0)", np.isclose(r[-1, c, c], 2.0)) fw.check("r = 2 m at (0,2,0)", np.isclose(r[c, -1, c], 2.0)) ``` -:::{admonition} Solution — Task 1 +:::{admonition} Solution — Task 3 :class: dropdown ```python @@ -171,7 +347,7 @@ r = distance_to(X, Y, Z) ``` ::: -A surface on which $R$ takes one fixed value is an **isosurface**, or level set — the three-dimensional version of a contour line on a map. +A surface on which $r$ takes one fixed value is an **isosurface**, or level set — the three-dimensional version of a contour line on a map. ```{code-cell} ipython3 fw.show_isosurfaces(X, Y, Z, r, levels=[0.5, 1.0, 1.5], label="r [m]", @@ -179,21 +355,29 @@ fw.show_isosurfaces(X, Y, Z, r, levels=[0.5, 1.0, 1.5], label="r [m]", ``` -### Task 2 — the gradient of the distance +### Task 4 — the gradient of the distance + +Do this one on paper first. Differentiating $r = \sqrt{x^2+y^2+z^2}$ by the chain rule, + +$$ \frac{\partial r}{\partial x} = \frac{x}{r}, \qquad \frac{\partial r}{\partial y} = \frac{y}{r}, \qquad \frac{\partial r}{\partial z} = \frac{z}{r} $$ -Compute $\nabla R$. Before you run anything, predict two things and write them down: **which way** the arrows point, and **how long** they are. +so, collecting the three components, -Then test the prediction quantitatively. The outward unit radial vector is $\hat{\mathbf{a}}_R = (x\,\hat{\mathbf{a}}_x + y\,\hat{\mathbf{a}}_y + z\,\hat{\mathbf{a}}_z)/R$, so the radial part of any vector field $\mathbf{A}$ is $\mathbf{A}\cdot\hat{\mathbf{a}}_R$. If $\nabla R$ is *purely* radial, that projection recovers its full magnitude. +$$ \nabla r \;=\; \frac{\partial r}{\partial x}\hat{\boldsymbol{x}} + \frac{\partial r}{\partial y}\hat{\boldsymbol{y}} + \frac{\partial r}{\partial z}\hat{\boldsymbol{z}} \;=\; \frac{x\,\hat{\boldsymbol{x}} + y\,\hat{\boldsymbol{y}} + z\,\hat{\boldsymbol{z}}}{r} \;=\; \hat{\boldsymbol{r}} $$ + +The last step is the definition of the outward unit radial vector: $\hat{\boldsymbol{r}}$ is exactly the position vector divided by its own length. So $\nabla r$ is a **unit** vector pointing **away** from the source — a direction and a magnitude you now know in advance. + +The code below checks whether a finite-difference gradient on a grid reproduces that. Two measurements: the magnitude, which should be 1; and the projection $\nabla r \cdot \hat{\boldsymbol{r}}$, which recovers the full magnitude only if the gradient is *purely* radial, with nothing left over along the sphere. ```{code-cell} ipython3 # The outward unit radial vector, used again later. -Rs = np.maximum(r, 1e-12) # 0/0 at the source is not a lesson -aRx, aRy, aRz = X / Rs, Y / Rs, Z / Rs +rs = np.maximum(r, 1e-12) # 0/0 at the source is not a lesson +rhx, rhy, rhz = X / rs, Y / rs, Z / rs -# Task 2 +# Task 4 # 1. grad r, as three components. # 2. Its magnitude. -# 3. Its projection onto a_R. +# 3. Its projection onto r-hat. # 4. Draw it, then rotate the figure and compare with the spheres above. grx, gry, grz = np.gradient(___, ___, ___, ___) @@ -212,42 +396,120 @@ fw.check_close("|grad r| = 1 everywhere", grad_r_mag, 1.0, rtol=0.05, where=band fw.check_close("grad r is purely radial", radial_part, 1.0, rtol=0.05, where=band) ``` -:::{admonition} Solution — Task 2 +:::{admonition} Solution — Task 4 :class: dropdown ```python grx, gry, grz = np.gradient(r, dx, dy, dz) grad_r_mag = np.sqrt(grx**2 + gry**2 + grz**2) -radial_part = grx * aRx + gry * aRy + grz * aRz +radial_part = grx * rhx + gry * rhy + grz * rhz print(f"|grad r| median in 0.4 < r < 1.6 m : " f"{np.median(grad_r_mag[(r > 0.4) & (r < 1.6)]):.4f}") ``` ::: -:::{admonition} The magnitude is 1. Everywhere. +:::{admonition} What the algebra means :class: important -Walk one metre directly away from the source and your distance from it grows by exactly one metre. The steepest rate of change of $R$ is 1 m/m, wherever you stand: +$\lvert\nabla r\rvert = 1$ needs no calculus to see: walk one metre directly away from the source and your distance from it grows by exactly one metre, so the steepest rate of change of $r$ is 1 m/m wherever you stand. A gradient carries the direction of steepest increase and a length equal to that rate — here, "away" and 1. + +The radial check fixes the other half: moving *along* a sphere does not change $r$, so the gradient has no component there. **$\nabla f$ is normal to the level surfaces of $f$** — for every scalar field, not just this one. + +The same chain rule settles the next two tasks in advance: $\nabla g(r) = \dfrac{dg}{dr}\,\hat{\boldsymbol{r}}$ for any $g$ depending on position only through $r$. Derive before you run. +::: + +### Task 5 — how fast does it change *that* way? + +The gradient's *direction* is settled: steepest increase, normal to the level surface. Its *magnitude* is the claim we have not tested. It follows from + +$$ dp = (\nabla p)\cdot d\boldsymbol{l} = \lvert\nabla p\rvert\,\lvert d\boldsymbol{l}\rvert\cos\psi +\qquad\Longrightarrow\qquad +\frac{dp}{dl} = \lvert\nabla p\rvert\cos\psi, $$ + +where $d\boldsymbol{l}$ is a small step in whatever direction you choose, $dl = \lvert d\boldsymbol{l}\rvert$ is its length, and $\psi$ is the angle between that step and the gradient. (The step is written $d\boldsymbol{l}$ rather than $d\boldsymbol{r}$ only because $r$ already means the distance from the origin on this page.) -$$ \nabla R = \hat{\mathbf{a}}_R $$ +Two things follow, and both are testable: the rate of change in *any* direction is $\lvert\nabla p\rvert\cos\psi$, and it can never exceed $\lvert\nabla p\rvert$ — reached only at $\psi = 0$. -The second check fixes the direction: moving *along* a sphere does not change $R$, so the gradient has no component there. **$\nabla f$ is normal to the level surfaces of $f$** — for every scalar field, not just this one. +Measure it. Pick one point, walk a short distance $\varepsilon$ along many different unit vectors $\hat{\boldsymbol{u}}$, and compare the measured rate against the prediction. -The chain rule now settles the next two tasks in advance: $\nabla g(R) = \dfrac{dg}{dR}\,\hat{\mathbf{a}}_R$ for any $g$ depending on position only through $R$. Predict before you run. +```{code-cell} ipython3 +p_field = 1.0 / np.maximum(r, 0.25) # any scalar field will do +gpx, gpy, gpz = np.gradient(p_field, dx, dy, dz) + +ip, jp, kp = 40, 36, 34 # one sample point, off-axis +gvec = np.array([gpx[ip, jp, kp], gpy[ip, jp, kp], gpz[ip, jp, kp]]) +point = np.array([axis[ip], axis[jp], axis[kp]]) + +def p_exact(q): + return 1.0 / np.linalg.norm(q) # the same field, evaluated anywhere + +# Task 5 -- fill in the four blanks; the plotting is given. +grad_mag = ___ # |grad p| at the point, from gvec + +rng = np.random.default_rng(0) +eps = 1e-4 +cosines, rates = [], [] +for _ in range(200): + u = rng.normal(size=3) + u = ___ # make it a UNIT vector + cosines.append(___) # cos(psi) = u . gvec / |grad p| + rates.append(___) # centred difference of p_exact + # along u, step eps, over 2*eps +cosines, rates = np.asarray(cosines), np.asarray(rates) + +# --- given: measurements against the predicted straight line --- +plt.figure(figsize=(5.6, 4.4)) +plt.scatter(cosines, rates, s=12, alpha=0.6, label="measured") +cs = np.linspace(-1, 1, 50) +plt.plot(cs, grad_mag*cs, "k", lw=1.5, label=r"$|\nabla p|\cos\psi$") +plt.xlabel(r"$\cos\psi$") +plt.ylabel(r"$dp/dl$ [m$^{-2}$]") +plt.legend(); plt.grid(alpha=0.3) +plt.show() + +# --- self-check (leave this alone) --- +slope = float(np.polyfit(cosines, rates, 1)[0]) +fw.check_scalar("fitted slope = |grad p|", slope, grad_mag, rtol=0.01) +fw.check("no direction beats |grad p|", np.max(np.abs(rates)) <= grad_mag * 1.001) +``` + +:::{admonition} Solution — Task 5 +:class: dropdown + +```python +grad_mag = float(np.linalg.norm(gvec)) + +# ... and inside the loop: + u = u / np.linalg.norm(u) + cosines.append(float(u @ gvec) / grad_mag) + rates.append((p_exact(point + eps*u) - p_exact(point - eps*u)) / (2*eps)) +``` +::: + +:::{admonition} The magnitude, earned +:class: important + +Every measured rate lies on the line. Three readings of the same picture: + +- **At $\cos\psi = 1$** you are walking straight up the gradient, and the rate equals $\lvert\nabla p\rvert$ exactly. Nothing beats it — that is what "steepest" means, now measured rather than asserted. +- **At $\cos\psi = 0$** you are moving along the level surface and $p$ does not change at all. This is the normality result of Task 4, arriving a second time by a different route. +- **At $\cos\psi = -1$** you get $-\lvert\nabla p\rvert$: the steepest *descent*, which is the direction $\boldsymbol{E} = -\nabla V$ will pick out in Part 2. + +One vector carries a direction *and* a rate, and the cosine tells you what you get for walking at an angle to it. ::: --- -## Part 2 — Invert it, and watch the arrows turn round +## Part 3 — Invert it, and watch the arrows turn round Now the function the physics actually uses: not the distance, but **one over** the distance, -$$ f(R) = \frac{1}{R}, \qquad\text{so}\qquad \nabla f = \frac{d}{dR}\!\left(\frac{1}{R}\right)\hat{\mathbf{a}}_R = -\frac{1}{R^{2}}\,\hat{\mathbf{a}}_R $$ +$$ f(r) = \frac{1}{r}, \qquad\text{so}\qquad \nabla f = \frac{d}{dr}\!\left(\frac{1}{r}\right)\hat{\boldsymbol{r}} = -\frac{1}{r^{2}}\,\hat{\boldsymbol{r}} $$ -Same spheres as isosurfaces — $f$ is constant wherever $R$ is constant. But the *ordering* has been turned inside out: $f$ is now largest near the source and decays to nothing far away. Predict what that does to the arrows, then check the prediction against the formula above, then measure it. +Same spheres as isosurfaces — $f$ is constant wherever $r$ is constant. But the *ordering* has been turned inside out: $f$ is now largest near the source and decays to nothing far away. Predict what that does to the arrows, then check the prediction against the formula above, then measure it. -### Task 3 — the gradient of the inverse distance +### Task 6 — the gradient of the inverse distance ```{code-cell} ipython3 # The mask keeps the singularity at r = 0 off the grid. Everything within @@ -255,14 +517,14 @@ Same spheres as isosurfaces — $f$ is constant wherever $R$ is constant. But th r_masked = np.where(r < 0.25, np.nan, r) f = 1.0 / r_masked -# Task 3 +# Task 6 # 1. grad f, as components fx, fy, fz; then its magnitude f_mag. The -# self-check compares it against the predicted 1/R^2. +# self-check compares it against the predicted 1/r^2. # 2. Draw it with normalise=True: every arrow the same length, so the # picture shows direction only. The magnitude is not lost -- it moves # into the colour, on a log scale (it spans three decades here). Pass # a label so the colorbar names the quantity, e.g. -# label="|∇(1/R)| [m-2]" -- plotly colorbars take +# label="|∇(1/r)| [m-2]" -- plotly colorbars take # Unicode and a little HTML, not LaTeX. fx, fy, fz = ___ @@ -276,7 +538,7 @@ fw.check_close("|grad(1/r)| = 1/r^2", f_mag, 1.0 / r_masked**2, rtol=0.05, where fw.check("grad(1/r) points inward at (1,0,0)", fx[-1 - 15, c, c] < 0) ``` -:::{admonition} Solution — Task 3 +:::{admonition} Solution — Task 6 :class: dropdown ```python @@ -298,31 +560,31 @@ fw.show_cones(X, Y, Z, fx, fy, fz, step=8, normalise=True, The arrows have reversed. Same spheres, same source, opposite direction: -$$ \nabla R = +\hat{\mathbf{a}}_R, \qquad\qquad \nabla\!\left(\frac{1}{R}\right) = -\frac{1}{R^{2}}\,\hat{\mathbf{a}}_R $$ +$$ \nabla r = +\hat{\boldsymbol{r}}, \qquad\qquad \nabla\!\left(\frac{1}{r}\right) = -\frac{1}{r^{2}}\,\hat{\boldsymbol{r}} $$ -Nothing about space changed. What changed is **which way the function climbs**. And the steepness changed too: $1/R$ climbs ever faster as you approach the source, so its gradient grows as $1/R^2$ rather than staying at 1. +Nothing about space changed. What changed is **which way the function climbs**. And the steepness changed too: $1/r$ climbs ever faster as you approach the source, so its gradient grows as $1/r^2$ rather than staying at 1. A gradient knows nothing about sources, sinks, charges or fields. It only knows uphill. ::: -### Task 4 — from geometry to physics +### Task 7 — from geometry to physics Here the physics enters, and it enters as a single minus sign. The electric potential of a point charge $Q$ is the inverse-distance function with a constant in front, -$$ V(R) = \frac{1}{4\pi\varepsilon_0}\frac{Q}{R}\quad[\text{V}], $$ +$$ V(r) = \frac{1}{4\pi\varepsilon_0}\frac{Q}{r}\quad[\text{V}], $$ and the electric field is *defined* as -$$ \mathbf{E} = -\nabla V \quad[\text{V/m}]. $$ +$$ \boldsymbol{E} = -\nabla V \quad[\text{V/m}]. $$ You already know what $\nabla V$ does: it points inward, uphill towards the charge. The minus sign turns it round, so **the field points downhill** — which is exactly the way a positive test charge released from rest would move, losing potential energy as it goes. ```{code-cell} ipython3 V = k_e * Q / r_masked -# Task 4 +# Task 7 # 1. E = -grad V, as components Ex, Ey, Ez; then E_mag. -# 2. Compare E_mag against the analytic k_e*Q/R^2 at a few radii, in V/m. +# 2. Compare E_mag against the analytic k_e*Q/r^2 at a few radii, in V/m. # 3. Draw it with normalise=True and confirm it points OUTWARD for Q > 0. Ex, Ey, Ez = ___ @@ -331,12 +593,12 @@ E_mag = ___ # --- self-check (leave this alone) --- -fw.check_close("|E| = Q/(4 pi eps0 R^2)", E_mag, k_e * Q / r_masked**2, +fw.check_close("|E| = Q/(4 pi eps0 r^2)", E_mag, k_e * Q / r_masked**2, rtol=0.05, where=outside) fw.check("E points outward at (1,0,0)", Ex[-1 - 15, c, c] > 0) ``` -:::{admonition} Solution — Task 4 +:::{admonition} Solution — Task 7 :class: dropdown ```python @@ -358,24 +620,24 @@ fw.show_cones(X, Y, Z, Ex, Ey, Ez, step=8, normalise=True, :::{admonition} Why bother with $V$ at all? :class: tip -$V$ is a scalar: one number per point, no direction to keep track of. $\mathbf{E}$ is a vector: three. Anything you can do once on $V$ and then differentiate is cheaper — in arithmetic and in bookkeeping — than doing it three times on $\mathbf{E}$. +$V$ is a scalar: one number per point, no direction to keep track of. $\boldsymbol{E}$ is a vector: three. Anything you can do once on $V$ and then differentiate is cheaper — in arithmetic and in bookkeeping — than doing it three times on $\boldsymbol{E}$. Part 3 is the first payoff, and it is the reason the potential is worth defining in the first place. ::: --- -## Part 3 — Two sources: superposition +## Part 4 — Two sources: superposition One charge is symmetric enough to be boring. Put down two: -$$ V_{\text{total}} = \frac{1}{4\pi\varepsilon_0}\left(\frac{Q_1}{R_1} + \frac{Q_2}{R_2}\right) $$ +$$ V_{\text{total}} = \frac{1}{4\pi\varepsilon_0}\left(\frac{Q_1}{r_1} + \frac{Q_2}{r_2}\right) $$ **Superposition** for the potential is nothing more than adding two numbers at every point, because $V$ is a scalar. Adding the two *fields* instead would mean a vector sum at every point in the cube. -Since $\nabla$ is a linear operator, $-\nabla(V_1 + V_2) = \mathbf{E}_1 + \mathbf{E}_2$ exactly. So the efficient route is: **add the potentials, then take one gradient at the very end.** Nothing is lost. +Since $\nabla$ is a linear operator, $-\nabla(V_1 + V_2) = \boldsymbol{E}_1 + \boldsymbol{E}_2$ exactly. So the efficient route is: **add the potentials, then take one gradient at the very end.** Nothing is lost. -### Task 5 — build a dipole +### Task 8 — build a dipole ```{code-cell} ipython3 # Distances to two sources on the x-axis. The guard only trips if a grid @@ -386,7 +648,7 @@ r_plus = np.where(distance_to(X, Y, Z, -0.5, 0.0, 0.0) < 0.01, np.nan, r_minus = np.where(distance_to(X, Y, Z, +0.5, 0.0, 0.0) < 0.01, np.nan, distance_to(X, Y, Z, +0.5, 0.0, 0.0)) -# Task 5 +# Task 8 # 1. Superpose the potentials of +Q at (-0.5, 0, 0) and -Q at (+0.5, 0, 0) # into V_dip. Scalar addition -- just a sum. # 2. Take ONE gradient, negate it: Ex_d, Ey_d, Ez_d. @@ -409,7 +671,7 @@ fw.check("V = 0 on the mid-plane", fw.check("E on the mid-plane points from + to -", np.nanmean(Ex_d[mid]) > 0) ``` -:::{admonition} Solution — Task 5 +:::{admonition} Solution — Task 8 :class: dropdown ```python @@ -428,9 +690,9 @@ plt.show() :::{admonition} Look at the mid-plane before you move on :class: tip -Halfway between the two charges, at $x = 0$, the potential is **exactly zero** — the two contributions cancel. Yet the field there is not zero at all: it is at its strongest, pointing straight from the positive charge to the negative one. +At $x = 0$, the potential is **exactly zero**. Yet the field there is not zero at all: it is at its strongest, pointing straight from the positive charge to the negative one. -The field is the *slope* of the potential, not its value. A landscape can be at sea level and still be steep. Notice also what the picture shows about direction: the streamlines cross the coloured contours at right angles everywhere, which is Task 2's normality result showing up in a field you did not construct radially. +The field is the *slope* of the potential, not its value. A landscape can be at sea level and still be steep. Notice also what the picture shows about direction: the streamlines cross the coloured contours at right angles everywhere, which is Task 4's normality result showing up in a field you did not construct radially. ::: The same object in three dimensions — positive and negative equipotential surfaces together, drawn transparent: @@ -442,26 +704,155 @@ fw.show_isosurfaces(X, Y, Z, np.nan_to_num(V_dip), levels=[-lobe, -lobe/3, lobe/ title="Equipotential surfaces of a dipole") ``` +### Task 9 — the same mathematics, as a geophysical survey + +Everything you just built was two charges in vacuum. Now change nothing about the mathematics and everything about the physics. + +Drive a current $I$ into the ground through one electrode and take it out through another, a distance $a$ apart. In ground of resistivity $\rho$ the current spreads through the **lower half-space only** — air does not conduct — so each electrode contributes $\rho I/2\pi r$ rather than $\rho I / 4\pi r$, and superposition gives + +$$ V(x,y,z) = \frac{\rho I}{2\pi}\left(\frac{1}{\lvert\boldsymbol{r}-\boldsymbol{a}/2\rvert} - \frac{1}{\lvert\boldsymbol{r}+\boldsymbol{a}/2\rvert}\right), \qquad z \ge 0 \ \text{(down into the ground)}. $$ + +The field follows as before, $\boldsymbol{E} = -\nabla V$, and Ohm's law in local form turns it into a **current density**: + +$$ \boldsymbol{J} = \rho^{-1}\boldsymbol{E} = -\rho^{-1}\nabla V \quad [\text{A}/\text{m}^2]. $$ + +This is a real measurement — a DC resistivity survey, the workhorse of near-surface geophysics. Map it two ways: on the ground surface, where the electrodes are planted, and on a vertical section cut down between them. + +:::{admonition} Careful — $\rho$ means something else here +:class: warning + +In this task $\rho$ is the **electrical resistivity** in Ω·m. In Task 13 it will be a charge density in C/m³, written $\rho_v$ to keep them apart. The symbol is overloaded across the whole subject; the units tell you which is which. +::: + +The ground is a half-space, so this needs its own grid: $x$ and $y$ still run $-L$ to $L$, but $z$ runs from $0$ (the surface) downwards. + +```{code-cell} ipython3 +rho, I, a_sep = 100.0, 1.0, 1.0 # ohm.m, ampere, electrode spacing [m] + +axis_g = np.linspace(-2.0, 2.0, 81) # x and y +depth = np.linspace(0.0, 2.0, 41) # z, into the ground +Xg, Yg, Zg = np.meshgrid(axis_g, axis_g, depth, indexing="ij") +dxg = axis_g[1] - axis_g[0] +dzg = depth[1] - depth[0] + +def dist_to(x0): + return np.sqrt((Xg - x0)**2 + Yg**2 + Zg**2) + +# Task 9 +# 1. V from the formula above: source at x = +a_sep/2, sink at x = -a_sep/2. +# Mask each distance below 0.12 m -- the electrodes are singular points. +# 2. J = -grad(V)/rho, as Jx, Jy, Jz. Pass dxg, dxg, dzg -- z is spaced +# differently from x and y on this grid. +# 3. Two panels, stacked: +# fig, axes = plt.subplots(2, 1, figsize=(7.5, 9)) +# fw.show_field_slice(Xg, Yg, Zg, Jx, Jy, background=V_dc, ax=axes[0], +# plane="z", label="$V$ [V]", title=...) +# fw.show_field_slice(Xg, Yg, Zg, Jx, Jz, background=V_dc, ax=axes[1], +# plane="y", label="$V$ [V]", title=...) +# plane="z" is the ground surface; plane="y" is the vertical section, +# and there the in-plane components are (Jx, Jz), not (Jx, Jy). +# Finish with axes[1].invert_yaxis() so depth runs downwards. + +V_dc = ___ +Jx, Jy, Jz = ___ + + + +# --- self-check (leave this alone) --- +mid_dc = np.abs(Xg) < 1e-9 +fw.check("V = 0 on the mid-plane between the electrodes", + np.nanmax(np.abs(V_dc[mid_dc])) < 1e-6 * np.nanmax(np.abs(V_dc))) +fw.check("current flows from the source towards the sink at the surface", + np.nanmean(Jx[mid_dc]) < 0) +``` + +:::{admonition} Solution — Task 9 +:class: dropdown + +```python +guard = 0.12 +d_src = np.where(dist_to(+a_sep/2) < guard, np.nan, dist_to(+a_sep/2)) +d_snk = np.where(dist_to(-a_sep/2) < guard, np.nan, dist_to(-a_sep/2)) +V_dc = rho * I / (2*np.pi) * (1/d_src - 1/d_snk) + +gVx, gVy, gVz = np.gradient(np.nan_to_num(V_dc), dxg, dxg, dzg) +Jx, Jy, Jz = -gVx/rho, -gVy/rho, -gVz/rho + +fig, axes = plt.subplots(2, 1, figsize=(7.5, 9)) +for ax_, comps, pl, ttl in ((axes[0], (Jx, Jy), "z", "a) ground surface, $z=0$"), + (axes[1], (Jx, Jz), "y", "b) vertical section, $y=0$")): + fw.show_field_slice(Xg, Yg, Zg, *comps, background=V_dc, ax=ax_, plane=pl, + label="$V$ [V]", density=1.2, title=ttl) +axes[1].invert_yaxis() # depth increases downwards +plt.tight_layout() +plt.show() +``` +::: + +Now use the field as an instrument. *All* the current injected at one electrode has to cross any closed surface you draw around it — there is nowhere else for it to go. Test that. + +```{code-cell} ipython3 +# The five faces of a box buried in the ground around one electrode. The top +# face is deliberately absent: it lies in the surface z = 0, where no current +# crosses into the air, so its contribution is zero by physics. +def buried_box_current(xc, hw=0.3): + i0 = int(np.argmin(np.abs(axis_g - (xc - hw)))) + i1 = int(np.argmin(np.abs(axis_g - (xc + hw)))) + j0 = int(np.argmin(np.abs(axis_g + hw))) + j1 = int(np.argmin(np.abs(axis_g - hw))) + k1 = int(np.argmin(np.abs(depth - hw))) + sx, sy, sz = slice(i0, i1+1), slice(j0, j1+1), slice(0, k1+1) + return (fw.area_integral(Jx[i1, sy, sz], dxg, dzg) - fw.area_integral(Jx[i0, sy, sz], dxg, dzg) + + fw.area_integral(Jy[sx, j1, sz], dxg, dzg) - fw.area_integral(Jy[sx, j0, sz], dxg, dzg) + + fw.area_integral(Jz[sx, sy, k1], dxg, dxg)) + +for xc, name in ((+a_sep/2, "source"), (-a_sep/2, "sink")): + print(f"current out of a box around the {name:6s}: {buried_box_current(xc):+7.4f} A") +print(f" injected: {I:+7.4f} A") + +# --- self-check (leave this alone) --- +fw.check_scalar("box around the source carries I", buried_box_current(+a_sep/2), I, rtol=0.01, unit=" A") +fw.check_scalar("box around the sink carries -I", buried_box_current(-a_sep/2), -I, rtol=0.01, unit=" A") +``` + +:::{admonition} Why five faces and not six? +:class: important + +The box is closed by the ground surface itself. Air does not conduct, so $J_z = 0$ at $z=0$ — a **boundary condition**, true by physics, not something to be measured. + +It is worth seeing what happens if you do try to measure it. `np.gradient` has no neighbour above $z=0$, so it falls back to a one-sided difference there, right beside a singular electrode — and reports about $-0.35$ A of current flowing into the sky. Including that face would corrupt a result that is otherwise good to 0.35%. + +The lesson generalises well beyond this lab: **where you know a boundary condition exactly, impose it — do not ask a finite-difference stencil to rediscover it.** Numerical derivatives are least trustworthy exactly where your domain stops. +::: + --- -## Part 4 — Divergence: is anything being created here? +:::{admonition} End of session 1 +:class: note + +Parts 1–4 are the gradient, and that is where the first afternoon ends. **Part 5 onwards needs the divergence**, which is lectured next — come back to it in the following session, or read ahead if you are curious. +::: + +--- + +## Part 5 — Divergence: is anything being created here? The gradient took a scalar and returned a vector. The divergence goes the other way — hand it a vector field, get back a scalar: -$$ \nabla\cdot\mathbf{A} \;=\; \lim_{\Delta v \to 0}\frac{1}{\Delta v}\oint_S \mathbf{A}\cdot d\mathbf{s} \;=\; \frac{\partial A_x}{\partial x} + \frac{\partial A_y}{\partial y} + \frac{\partial A_z}{\partial z} $$ +$$ \nabla\cdot\boldsymbol{A} \;=\; \lim_{\Delta v \to 0}\frac{1}{\Delta v}\oint_S \boldsymbol{A}\cdot d\boldsymbol{s} \;=\; \frac{\partial A_x}{\partial x} + \frac{\partial A_y}{\partial y} + \frac{\partial A_z}{\partial z} $$ -Read the definition on the left, not the formula on the right: **treat $\mathbf{A}$ as the velocity of a fluid**, put a small box anywhere, and measure the net outflow through its walls per unit volume. +Read the definition on the left, not the formula on the right: **treat $\boldsymbol{A}$ as the velocity of a fluid**, put a small box anywhere, and measure the net outflow through its walls per unit volume. -| $\nabla\cdot\mathbf{A}$ | Name | Picture | +| $\nabla\cdot\boldsymbol{A}$ | Name | Picture | | :---: | :--- | :--- | | $> 0$ | **source** | a tap — more leaves than arrives | | $< 0$ | **sink** | a drain — more arrives than leaves | | $= 0$ | **solenoidal** | whatever flows in, flows out | -### Task 6 — write the divergence +### Task 10 — write the divergence ```{code-cell} ipython3 -# Task 6 +# Task 10 # Write divergence(Ax, Ay, Az, dx, dy, dz) returning # dAx/dx + dAy/dy + dAz/dz -- one derivative along one axis per component. # np.gradient(Ax, dx, axis=0) gives dAx/dx and nothing else; asking it for @@ -479,7 +870,7 @@ fw.check_close("div of the position vector = 3", divergence(X, Y, Z, dx, dy, dz), 3.0, rtol=1e-6) ``` -:::{admonition} Solution — Task 6 +:::{admonition} Solution — Task 10 :class: dropdown ```python @@ -490,15 +881,136 @@ def divergence(Ax, Ay, Az, dx, dy, dz): ``` ::: -### Task 7 — three flows +### Task 11 — the only incompressible radial flow + +A first use of the operator. Water of constant density flows outward from a source at the origin. Away from that source nothing is created or destroyed, so the flow must be **incompressible**: + +$$ \nabla\cdot\boldsymbol{v} = 0 \qquad \text{for } r \neq 0. $$ + +Constant density and a point source force the flow to be radial, $\boldsymbol{v} = f(r)\,\boldsymbol{r}$, and incompressibility then pins $f$ down completely: + +$$ \nabla\cdot\boldsymbol{v} = 3f(r) + r\frac{df}{dr} = 0 \qquad\Longrightarrow\qquad f(r) = \frac{A}{r^{3}}. $$ + +Do not take that on trust — find it. Try four candidates and let the divergence pick. + +```{code-cell} ipython3 +# Task 11 +# For f(r) = const, 1/r^2, 1/r^3, 1/r^4, build v = f(r) * (X, Y, Z) using +# r_safe below, take the divergence, and report a scale-free measure of how +# far each is from zero: median |div v| / median(|v|/r) over the test band. +# Only one candidate should come out near zero. + +r_safe = np.where(r < 0.3, np.nan, r) +band_i = interior & (r > 0.6) & (r < 1.6) + +for name, f_r in [("const", np.ones_like(r_safe)), + ("1/r^2", 1/r_safe**2), + ("1/r^3", 1/r_safe**3), + ("1/r^4", 1/r_safe**4)]: + pass # replace this loop body with your own + + + +# --- self-check (leave this alone) --- +_v = 1/r_safe**3 +_d = divergence(*(np.nan_to_num(_v*q) for q in (X, Y, Z)), dx, dy, dz) +_scale = np.nanmedian(np.abs(np.sqrt(3)*_v*r_safe/r_safe)[band_i]) +fw.check("1/r^3 is the divergence-free one", + np.nanmedian(np.abs(_d[band_i])) / _scale < 0.05) +``` + +:::{admonition} Solution — Task 11 +:class: dropdown + +```python +for name, f_r in [("const", np.ones_like(r_safe)), + ("1/r^2", 1/r_safe**2), + ("1/r^3", 1/r_safe**3), + ("1/r^4", 1/r_safe**4)]: + vx, vy, vz = f_r*X, f_r*Y, f_r*Z + d = divergence(np.nan_to_num(vx), np.nan_to_num(vy), np.nan_to_num(vz), dx, dy, dz) + scale = np.nanmedian((np.sqrt(vx**2 + vy**2 + vz**2) / r_safe)[band_i]) + print(f" f = {name:6s}: median |div v| / (|v|/r) = {np.nanmedian(np.abs(d[band_i]))/scale:8.2%}") +``` +::: + +:::{admonition} Where the inverse-square law comes from +:class: important + +Three candidates sit near 100%; one sits under 1%. Only $f = A/r^{3}$ survives, exactly as the algebra says — and note what that means for the field itself: + +$$ \boldsymbol{v} = \frac{A}{r^{3}}\boldsymbol{r} = \frac{A}{r^{2}}\,\hat{\boldsymbol{r}}. $$ + +**That is the same $1/r^{2}$ you have been working with since Task 6.** Here it was not assumed, and no charge was mentioned: it fell out of "nothing is created away from the source" plus "space is three-dimensional". The surface of a sphere grows as $r^{2}$, so a fixed amount of stuff crossing it must thin as $1/r^{2}$. + +Coulomb's law, Newton's gravity and this water all share an exponent for that one geometric reason. +::: + +### Task 11, continued — a field with no source anywhere + +Notice the small print on that result: $\nabla\cdot\boldsymbol{v} = 0$ **for $r \neq 0$**. The origin is excluded, and it has to be — that is where the water is injected. Put a closed surface around it and you would find the tap. + +Now a field with no such exception. To first order the Earth's magnetic field is a **dipole**: a north and a south pole so close together that they coincide. With dipole moment $\boldsymbol{m}$ pointing from south to north, + +$$ \boldsymbol{B} = \frac{3\boldsymbol{r}\,(\boldsymbol{r}\cdot\boldsymbol{m}) - r^{2}\boldsymbol{m}}{r^{5}}. $$ + +Take $\boldsymbol{m} = \hat{\boldsymbol{z}}$ and measure its divergence with the same function. + +```{code-cell} ipython3 +# Task 11, continued -- fill in the three components. +# With m = z-hat, the dot product r . m is simply Z. +# Careful with the second term: it appears only in the z-component. + +r_dot_m = Z +Bx = ___ +By = ___ +Bz = ___ + +div_B = divergence(np.nan_to_num(Bx), np.nan_to_num(By), np.nan_to_num(Bz), dx, dy, dz) + +# --- given: the same scale-free measure as above --- +B_mag = np.sqrt(Bx**2 + By**2 + Bz**2) +print(f" dipole B : median |div B| / (|B|/r) = " + f"{np.nanmedian(np.abs(div_B[band_i]) / (B_mag/r_safe)[band_i]):8.2%}") + +# --- self-check (leave this alone) --- +fw.check("B is divergence-free", + np.nanmedian(np.abs(div_B[band_i]) / (B_mag/r_safe)[band_i]) < 0.05) +fw.check("B is not simply radial (it has a north and a south)", + np.nanmin((Bx*X + By*Y + Bz*Z)[band_i]) < 0) +``` + +:::{admonition} Solution — Task 11, continued +:class: dropdown + +```python +Bx = 3*X*r_dot_m / r_safe**5 +By = 3*Y*r_dot_m / r_safe**5 +Bz = (3*Z*r_dot_m - r_safe**2) / r_safe**5 +``` +::: + +:::{admonition} No magnetic monopoles +:class: important + +Both fields are divergence-free where you measured, but they are not the same statement. + +The water needed an exclusion: $\nabla\cdot\boldsymbol{v} = 0$ *away from the origin*, because the origin is a tap. The dipole needs none — $\nabla\cdot\boldsymbol{B} = 0$ holds **everywhere in space, including at the source itself**. There is no point you could exclude and find a magnet leaking field the way the tap leaks water. That is one of Maxwell's equations, and it says magnetic monopoles do not exist: field lines of $\boldsymbol{B}$ never begin and never end, they only close on themselves. + +Two footnotes on the numbers. The dipole's median error, near 1.8%, is worse than the radial flow's 0.7% — not because the physics is shakier but because $\boldsymbol{B}$ falls off as $1/r^{3}$ instead of $1/r^{2}$, so a centred difference has more curvature to miss. Part 6 will make the "no exception" claim exactly rather than to 2%, by putting a closed surface around the dipole instead of differentiating it. + +And the second check is worth a moment: $\boldsymbol{B}\cdot\boldsymbol{r}$ goes negative somewhere, which the outward flow of Task 11 never does. The dipole points *inward* over part of space — it returns. That is what "closes on itself" looks like in a number. +::: + +### Task 12 — three flows Three velocity fields. For each: **sketch it in your head, predict the sign of the divergence, then measure.** Write the predictions down first — the point of this task is the gap between intuition and the answer. -| | Field $\mathbf{A}$ | What it looks like | +| | Field $\boldsymbol{A}$ | What it looks like | | :---: | :--- | :--- | -| **(a)** | $x\,\hat{\mathbf{a}}_x + y\,\hat{\mathbf{a}}_y + z\,\hat{\mathbf{a}}_z$ | flow rushing outward in all directions | -| **(b)** | $-y\,\hat{\mathbf{a}}_x + x\,\hat{\mathbf{a}}_y$ | fluid rotating about the $z$-axis | -| **(c)** | $x\,\hat{\mathbf{a}}_x - y\,\hat{\mathbf{a}}_y$ | stretching along $x$, squeezing along $y$ | +| **(a)** | $x\,\hat{\boldsymbol{x}} + y\,\hat{\boldsymbol{y}} + z\,\hat{\boldsymbol{z}}$ | flow rushing outward in all directions | +| **(b)** | $-y\,\hat{\boldsymbol{x}} + x\,\hat{\boldsymbol{y}}$ | fluid rotating about the $z$-axis | +| **(c)** | $x\,\hat{\boldsymbol{x}} - y\,\hat{\boldsymbol{y}}$ | stretching along $x$, squeezing along $y$ | ```{code-cell} ipython3 # Commit to your predictions BEFORE the next cell: +1 for a source, -1 for a @@ -507,9 +1019,9 @@ predictions = {"a": ___, "b": ___, "c": ___} ``` ```{code-cell} ipython3 -# Task 7 +# Task 12 # 1. Build the three fields as triples of arrays. -# 2. Take the divergence of each with your Task 6 function, as div_a, +# 2. Take the divergence of each with your Task 10 function, as div_a, # div_b and div_c -- the self-check needs those names. Print the mean # of each. # 3. Draw fields (a) and (c) side by side in the z = 0 plane, streamlines @@ -517,7 +1029,7 @@ predictions = {"a": ___, "b": ___, "c": ___} # so the colours are comparable: # fig, axes = plt.subplots(1, 2, figsize=(12, 4.6)) # fw.show_field_slice(X, Y, Z, *Aa[:2], background=div_a, ax=axes[0], -# vmin=-3, vmax=3, label=r"$\nabla\cdot\mathbf{A}$", +# vmin=-3, vmax=3, label=r"$\nabla\cdot\boldsymbol{A}$", # title="(a) outward flow") # ... and the same for (c) with Ac and div_c. # Look hard at the two before reading the note below. @@ -537,7 +1049,7 @@ for key, measured in (("a", div_a), ("b", div_b), ("c", div_c)): print(f" ({key}) you said {predictions[key]:+d}, measured {sign:+d} -- {verdict}") ``` -:::{admonition} Solution — Task 7 +:::{admonition} Solution — Task 12 :class: dropdown ```python @@ -559,7 +1071,7 @@ for ax_, (name, A, d) in zip(axes, [("(a) outward flow", Aa, div_a), ("(c) shear flow", Ac, div_c)]): fw.show_field_slice(X, Y, Z, *A[:2], background=d, ax=ax_, density=1.1, vmin=-3, vmax=3, colorbar=(ax_ is axes[-1]), - label=r"$\nabla\cdot\mathbf{A}$ [s$^{-1}$]", title=name) + label=r"$\nabla\cdot\boldsymbol{A}$ [s$^{-1}$]", title=name) plt.tight_layout() plt.show() ``` @@ -570,95 +1082,95 @@ plt.show() Along the $x$-axis, field (c) rushes outward. It looks like a source. It is not: -$$ \nabla\cdot\mathbf{A} = \frac{\partial}{\partial x}(x) + \frac{\partial}{\partial y}(-y) = 1 - 1 = 0 $$ +$$ \nabla\cdot\boldsymbol{A} = \frac{\partial}{\partial x}(x) + \frac{\partial}{\partial y}(-y) = 1 - 1 = 0 $$ Put a box at the origin: fluid pours out through the left and right walls and in through the top and bottom at exactly the same rate. The parcel changes **shape**, never **volume**. -*Arrows pointing apart* is not divergence. Outflow in one direction can be cancelled exactly by inflow in another — and in Task 9 you will put a closed surface around this field and measure that cancellation, rather than take it on the strength of this paragraph. +*Arrows pointing apart* is not divergence. Outflow in one direction can be cancelled exactly by inflow in another — and in Task 14 you will put a closed surface around this field and measure that cancellation, rather than take it on the strength of this paragraph. ::: -### Task 8 — the divergence as a charge detector +### Task 13 — the divergence as a charge detector Maxwell's first equation says -$$ \nabla\cdot\mathbf{E} = \frac{\rho}{\varepsilon_0} $$ +$$ \nabla\cdot\boldsymbol{E} = \frac{\rho_v}{\varepsilon_0} $$ -which is a strong claim: **the divergence of $\mathbf{E}$ at a point tells you the charge density at that point and nothing else.** Wherever there is no charge, $\mathbf{E}$ is solenoidal, however dramatically its arrows spread out. +which is a strong claim: **the divergence of $\boldsymbol{E}$ at a point tells you the charge density at that point and nothing else.** Wherever there is no charge, $\boldsymbol{E}$ is solenoidal, however dramatically its arrows spread out. Test that pointwise on a real source. Not a point charge — that is an idealisation with infinite density at one location, and no grid can hold it. Take instead a charge **smeared over a finite blob**, which is what any actual charged object is: -$$ \rho(R) = \rho_0\,e^{-R^{2}/a^{2}}, \qquad \rho_0 = 10^{-9}\ \text{C/m}^3, \qquad a = 0.5\ \text{m} $$ +$$ \rho_v(r) = \rho_{v0}\,e^{-r^{2}/a^{2}}, \qquad \rho_{v0} = 10^{-9}\ \text{C/m}^3, \qquad a = 0.5\ \text{m} $$ -Integrating that over a sphere of radius $R$ gives the charge it encloses (bookwork — you do not need to do the integral now): +Integrating that over a sphere of radius $r$ gives the charge it encloses (bookwork — you do not need to do the integral now): -$$ Q_{\text{enc}}(R) = \int_0^{R}\!\rho\,4\pi R'^{2}\,dR' = 4\pi\rho_0\left[\frac{a^{3}\sqrt{\pi}}{4}\operatorname{erf}\!\left(\frac{R}{a}\right) - \frac{a^{2}R}{2}e^{-R^{2}/a^{2}}\right] $$ +$$ Q_{\text{enc}}(r) = \int_0^{r}\!\rho_v\,4\pi r'^{2}\,dr' = 4\pi\rho_{v0}\left[\frac{a^{3}\sqrt{\pi}}{4}\operatorname{erf}\!\left(\frac{r}{a}\right) - \frac{a^{2}r}{2}e^{-r^{2}/a^{2}}\right] $$ -and Gauss's law in the form you already know, $E_R = Q_{\text{enc}}/4\pi\varepsilon_0R^{2}$, then gives the field — the $4\pi$ cancelling: +and Gauss's law, $E_r = Q_{\text{enc}}/4\pi\varepsilon_0r^{2}$, then gives the field — the $4\pi$ cancelling: -$$ E_R(R) = \frac{\rho_0}{\varepsilon_0 R^{2}}\left[\frac{a^{3}\sqrt{\pi}}{4}\operatorname{erf}\!\left(\frac{R}{a}\right) - \frac{a^{2}R}{2}e^{-R^{2}/a^{2}}\right] $$ +$$ E_r(r) = \frac{\rho_{v0}}{\varepsilon_0 r^{2}}\left[\frac{a^{3}\sqrt{\pi}}{4}\operatorname{erf}\!\left(\frac{r}{a}\right) - \frac{a^{2}r}{2}e^{-r^{2}/a^{2}}\right] $$ -Check it at small $R$ before trusting it. There $Q_{\text{enc}} \to \frac{4}{3}\pi R^{3}\rho_0$, so $E_R \to \rho_0R/3\varepsilon_0$: the field **rises linearly** from zero at the centre, because the charge enclosed grows faster than the $R^{2}$ of the surface. It peaks near $R \approx a$ and only then falls off. +One sanity check: near the centre $Q_{\text{enc}}$ grows as $r^{3}$ while the surface grows as $r^{2}$, so $E_r \to \rho_{v0} r/3\varepsilon_0$ — zero at the centre, rising linearly, peaking at $r \approx a$. ```{code-cell} ipython3 from scipy.special import erf -a, rho0 = 0.5, 1e-9 - -# Task 8 -# 1. rho = rho0 * exp(-r^2 / a^2) on the grid. -# 2. E_R from the formula above, using Rs in the denominators. (The two -# bracketed terms very nearly cancel for R << a, so the closed form -# loses accuracy below R ~ 1e-6 m; on this grid the only such sample -# is the origin, where the a_R components are zero anyway.) -# 3. Turn the radial magnitude into components along a_R: -# Ex_b = E_R * aRx, and likewise for y and z. -# 4. div_blob = divergence(...), and compare it against rho / epsilon_0 +a, rho_v0 = 0.5, 1e-9 + +# Task 13 +# 1. rho_v = rho_v0 * exp(-r^2 / a^2) on the grid. +# 2. E_r from the formula above, using rs in the denominators. (The two +# bracketed terms very nearly cancel for r << a, so the closed form +# loses accuracy below r ~ 1e-6 m; on this grid the only such sample +# is the origin, where the r-hat components are zero anyway.) +# 3. Turn the radial magnitude into components along r-hat: +# Ex_b = E_r * rhx, and likewise for y and z. +# 4. div_blob = divergence(...), and compare it against rho_v / epsilon_0 # everywhere -- including inside the source. # 5. Plot both, side by side, in the z = 0 plane. Pass the SAME vmin and # vmax to each panel, or they get separate auto-scales and the two # pictures are no longer comparable -- which is the whole point: -# hi = float(np.nanmax(rho / epsilon_0)) +# hi = float(np.nanmax(rho_v / epsilon_0)) # fig, axes = plt.subplots(1, 2, figsize=(12, 4.4)) # fw.show_scalar_slice(X, Y, Z, div_blob, ax=axes[0], cmap="magma", # vmin=0, vmax=hi, label=..., title=...) -# fw.show_scalar_slice(X, Y, Z, rho / epsilon_0, ax=axes[1], ...) +# fw.show_scalar_slice(X, Y, Z, rho_v / epsilon_0, ax=axes[1], ...) # Write your code here: # --- self-check (leave this alone) --- -peak = np.nanmax(rho / epsilon_0) -_e = np.abs(div_blob[interior] - (rho / epsilon_0)[interior]) / peak +peak = np.nanmax(rho_v / epsilon_0) +_e = np.abs(div_blob[interior] - (rho_v / epsilon_0)[interior]) / peak cart_worst, cart_median = float(_e.max()), float(np.median(_e)) -fw.check(f"div E = rho/eps0 pointwise (worst {cart_worst:.2%} of peak)", - cart_worst < 0.05, "check the component construction Ex_b = E_R * aRx") +fw.check(f"div E = rho_v/eps0 pointwise (worst {cart_worst:.2%} of peak)", + cart_worst < 0.05, "check the component construction Ex_b = E_r * rhx") ``` -:::{admonition} Solution — Task 8 +:::{admonition} Solution — Task 13 :class: dropdown ```python -rho = rho0 * np.exp(-r**2 / a**2) +rho_v = rho_v0 * np.exp(-r**2 / a**2) -E_R = rho0 / (epsilon_0 * Rs**2) * ( - (a**3 * np.sqrt(np.pi) / 4) * erf(Rs / a) - (a**2 * Rs / 2) * np.exp(-Rs**2 / a**2) +E_r = rho_v0 / (epsilon_0 * rs**2) * ( + (a**3 * np.sqrt(np.pi) / 4) * erf(rs / a) - (a**2 * rs / 2) * np.exp(-rs**2 / a**2) ) -Ex_b, Ey_b, Ez_b = E_R * aRx, E_R * aRy, E_R * aRz +Ex_b, Ey_b, Ez_b = E_r * rhx, E_r * rhy, E_r * rhz div_blob = divergence(Ex_b, Ey_b, Ez_b, dx, dy, dz) -hi = float(np.nanmax(rho / epsilon_0)) +hi = float(np.nanmax(rho_v / epsilon_0)) units = r"[V m$^{-2}$]" fig, axes = plt.subplots(1, 2, figsize=(12, 4.4)) fw.show_scalar_slice(X, Y, Z, div_blob, ax=axes[0], cmap="magma", label=units, - vmin=0, vmax=hi, title=r"measured $\nabla\cdot\mathbf{E}$") -fw.show_scalar_slice(X, Y, Z, rho / epsilon_0, ax=axes[1], cmap="magma", label=units, - vmin=0, vmax=hi, title=r"actual $\rho/\varepsilon_0$") + vmin=0, vmax=hi, title=r"measured $\nabla\cdot\boldsymbol{E}$") +fw.show_scalar_slice(X, Y, Z, rho_v / epsilon_0, ax=axes[1], cmap="magma", label=units, + vmin=0, vmax=hi, title=r"actual $\rho_v/\varepsilon_0$") plt.tight_layout() plt.show() -print(f"peak of rho/eps0 : {np.nanmax(rho/epsilon_0):8.2f}") +print(f"peak of rho_v/eps0 : {np.nanmax(rho_v/epsilon_0):8.2f}") print(f"peak of measured div: {np.nanmax(div_blob):8.2f}") ``` ::: @@ -675,37 +1187,37 @@ Notice where the divergence vanishes: everywhere outside the blob, where the fie Everything so far used the Cartesian formula, because `np.gradient` differentiates along array axes. But the divergence *is* flux per unit volume — a physical quantity, which cannot depend on the axes you happened to choose. Only the formula changes: -| | Gradient $\nabla T$ | Divergence $\nabla\cdot\mathbf{A}$ | +| | Gradient $\nabla T$ | Divergence $\nabla\cdot\boldsymbol{A}$ | | :--- | :--- | :--- | -| Cartesian $(x,y,z)$ | $\dfrac{\partial T}{\partial x}\hat{\mathbf{a}}_x + \dfrac{\partial T}{\partial y}\hat{\mathbf{a}}_y + \dfrac{\partial T}{\partial z}\hat{\mathbf{a}}_z$ | $\dfrac{\partial A_x}{\partial x} + \dfrac{\partial A_y}{\partial y} + \dfrac{\partial A_z}{\partial z}$ | -| Cylindrical $(r,\phi,z)$ | $\dfrac{\partial T}{\partial r}\hat{\mathbf{a}}_r + \dfrac{1}{r}\dfrac{\partial T}{\partial \phi}\hat{\mathbf{a}}_\phi + \dfrac{\partial T}{\partial z}\hat{\mathbf{a}}_z$ | $\dfrac{1}{r}\dfrac{\partial (rA_r)}{\partial r} + \dfrac{1}{r}\dfrac{\partial A_\phi}{\partial \phi} + \dfrac{\partial A_z}{\partial z}$ | -| Spherical $(R,\theta,\phi)$ | $\dfrac{\partial T}{\partial R}\hat{\mathbf{a}}_R + \dfrac{1}{R}\dfrac{\partial T}{\partial \theta}\hat{\mathbf{a}}_\theta + \dfrac{1}{R\sin\theta}\dfrac{\partial T}{\partial \phi}\hat{\mathbf{a}}_\phi$ | $\dfrac{1}{R^{2}}\dfrac{\partial (R^{2}A_R)}{\partial R} + \dfrac{1}{R\sin\theta}\dfrac{\partial (A_\theta \sin\theta)}{\partial \theta} + \dfrac{1}{R\sin\theta}\dfrac{\partial A_\phi}{\partial \phi}$ | +| Cartesian $(x,y,z)$ | $\dfrac{\partial T}{\partial x}\hat{\boldsymbol{x}} + \dfrac{\partial T}{\partial y}\hat{\boldsymbol{y}} + \dfrac{\partial T}{\partial z}\hat{\boldsymbol{z}}$ | $\dfrac{\partial A_x}{\partial x} + \dfrac{\partial A_y}{\partial y} + \dfrac{\partial A_z}{\partial z}$ | +| Cylindrical $(\varrho,\phi,z)$ | $\dfrac{\partial T}{\partial \varrho}\hat{\boldsymbol{\varrho}} + \dfrac{1}{\varrho}\dfrac{\partial T}{\partial \phi}\hat{\boldsymbol{\phi}} + \dfrac{\partial T}{\partial z}\hat{\boldsymbol{z}}$ | $\dfrac{1}{\varrho}\dfrac{\partial (\varrho v_\varrho)}{\partial \varrho} + \dfrac{1}{\varrho}\dfrac{\partial v_\phi}{\partial \phi} + \dfrac{\partial v_z}{\partial z}$ | +| Spherical $(r,\phi,\theta)$ | $\dfrac{\partial T}{\partial r}\hat{\boldsymbol{r}} + \dfrac{1}{r}\dfrac{\partial T}{\partial \theta}\hat{\boldsymbol{\theta}} + \dfrac{1}{r\sin\theta}\dfrac{\partial T}{\partial \phi}\hat{\boldsymbol{\phi}}$ | $\dfrac{1}{r^{2}}\dfrac{\partial (r^{2}v_r)}{\partial r} + \dfrac{1}{r\sin\theta}\dfrac{\partial (v_\theta \sin\theta)}{\partial \theta} + \dfrac{1}{r\sin\theta}\dfrac{\partial v_\phi}{\partial \phi}$ | -Cylindrical $r$ is the distance from the $z$-axis; spherical $R$, used throughout this lab, is the distance from the origin. +Cylindrical $\varrho=\sqrt{x^2+y^2}$ is the distance from the $z$-axis; spherical $r=\sqrt{x^2+y^2+z^2}$, used throughout this lab, is the distance from the origin. They are written differently precisely to keep them apart. -Both fields you have built are spherically symmetric — $\mathbf{E} = E_R(R)\,\hat{\mathbf{a}}_R$, with no $\theta$ or $\phi$ dependence — so two of the three spherical terms vanish and the divergence collapses to one ordinary derivative along one line: +Both fields you have built are spherically symmetric — $\boldsymbol{E} = E_r(r)\,\hat{\boldsymbol{r}}$, with no $\theta$ or $\phi$ dependence — so two of the three spherical terms vanish and the divergence collapses to one ordinary derivative along one line: -$$ \nabla\cdot\mathbf{E} \;=\; \frac{1}{R^{2}}\frac{d}{dR}\!\left(R^{2}E_R\right) $$ +$$ \nabla\cdot\boldsymbol{E} \;=\; \frac{1}{r^{2}}\frac{d}{dr}\!\left(r^{2}E_r\right) $$ ```{code-cell} ipython3 -dR = 0.005 -R_line = np.arange(0.05, 2.0 + dR, dR) # one radial line, not a cube +dr = 0.005 +r_line = np.arange(0.05, 2.0 + dr, dr) # one radial line, not a cube -# the same two fields as before, as functions of R alone -E_R_blob = rho0 / (epsilon_0 * R_line**2) * ( - (a**3 * np.sqrt(np.pi) / 4) * erf(R_line / a) - - (a**2 * R_line / 2) * np.exp(-R_line**2 / a**2)) -E_R_point = k_e * Q / R_line**2 +# the same two fields as before, as functions of r alone +E_R_blob = rho_v0 / (epsilon_0 * r_line**2) * ( + (a**3 * np.sqrt(np.pi) / 4) * erf(r_line / a) + - (a**2 * r_line / 2) * np.exp(-r_line**2 / a**2)) +E_r_point = k_e * Q / r_line**2 -div_blob_sph = np.gradient(R_line**2 * E_R_blob, dR) / R_line**2 -div_point_sph = np.gradient(R_line**2 * E_R_point, dR) / R_line**2 +div_blob_sph = np.gradient(r_line**2 * E_R_blob, dr) / r_line**2 +div_point_sph = np.gradient(r_line**2 * E_r_point, dr) / r_line**2 -rho_line = rho0 * np.exp(-R_line**2 / a**2) -err_sph = np.abs(div_blob_sph - rho_line / epsilon_0)[1:-1] / np.max(rho_line / epsilon_0) -print(f"blob : {R_line.size} samples on a line vs {X.size:,} in the cube") +rho_v_line = rho_v0 * np.exp(-r_line**2 / a**2) +err_sph = np.abs(div_blob_sph - rho_v_line / epsilon_0)[1:-1] / np.max(rho_v_line / epsilon_0) +print(f"blob : {r_line.size} samples on a line vs {X.size:,} in the cube") print(f" worst error {err_sph.max():.3%} of peak, median {np.median(err_sph):.4%}") -print(f" Cartesian, from Task 8: {cart_worst:.3%} and {cart_median:.4%}") -print(f"point: R^2 E_R varies by {np.ptp(R_line**2 * E_R_point):.1e} over the whole line") +print(f" Cartesian, from Task 13: {cart_worst:.3%} and {cart_median:.4%}") +print(f"point: r^2 E_r varies by {np.ptp(r_line**2 * E_r_point):.1e} over the whole line") print(f" max |div E| = {np.abs(div_point_sph).max():.1e}") ``` @@ -714,24 +1226,24 @@ print(f" max |div E| = {np.abs(div_point_sph).max():.1e}") Same field, same operator, same answer — from a few hundred samples on a line instead of a quarter of a million in a cube, and several times more accurately. -For the point charge the gain is not accuracy but certainty. $R^{2}E_R = q/4\pi\varepsilon_0$ is a **constant**, so its derivative is exactly zero for every $R>0$ — not "1.35% of something", but zero. Cartesian coordinates could only ever report that the divergence was small. +For the point charge the gain is not accuracy but certainty. $r^{2}E_r = q/4\pi\varepsilon_0$ is a **constant**, so its derivative is exactly zero for every $r>0$ — not "1.35% of something", but zero. Cartesian coordinates could only ever report that the divergence was small. Match your coordinates to the symmetry of the source and three noisy numerical derivatives collapse into one line of algebra. That is what the second and third rows of the table are for. ::: --- -## Part 5 — Flux, and the divergence theorem +## Part 6 — Flux, and the divergence theorem -Part 4 used the *differential* form of Gauss's law, which compares two numbers at one point. The *integral* form connects a volume to the surface enclosing it: +Part 5 used the *differential* form of Gauss's law, which compares two numbers at one point. The *integral* form connects a volume to the surface enclosing it: -$$ \oint_S \mathbf{E}\cdot d\mathbf{s} \;=\; \int_v \nabla\cdot\mathbf{E}\;dv \;=\; \frac{Q_{\text{enc}}}{\varepsilon_0} $$ +$$ \oint_S \boldsymbol{E}\cdot d\boldsymbol{s} \;=\; \int_v \nabla\cdot\boldsymbol{E}\;dv \;=\; \frac{Q_{\text{enc}}}{\varepsilon_0} $$ -The first equality is the **divergence theorem** — pure vector calculus, true for any well-behaved field. The second is the physics. Together: measuring $\mathbf{E}$ on a closed surface tells you how much charge is inside, and nothing about how it is arranged, or about any charge outside. +The first equality is the **divergence theorem** — pure vector calculus, true for any well-behaved field. The second is the physics. Together: measuring $\boldsymbol{E}$ on a closed surface tells you how much charge is inside, and nothing about how it is arranged, or about any charge outside. -Take $S$ to be a cube of half-width $h$ centred on the origin, faces on grid planes. On the $+x$ face the outward normal is $+\hat{\mathbf{a}}_x$, so it contributes $\int\!\!\int E_x\,dy\,dz$; on the $-x$ face the normal is $-\hat{\mathbf{a}}_x$ and the same integral enters negatively. Six faces, three pairs. +Take $S$ to be a cube of half-width $h$ centred on the origin, faces on grid planes. On the $+x$ face the outward normal is $+\hat{\boldsymbol{x}}$, so it contributes $\int\!\!\int E_x\,dy\,dz$; on the $-x$ face the normal is $-\hat{\boldsymbol{x}}$ and the same integral enters negatively. Six faces, three pairs. -### Task 9 — close the surface +### Task 14 — close the surface ```{code-cell} ipython3 # `fw.area_integral(F2, da, db)` integrates a 2-D array over the face it @@ -760,16 +1272,16 @@ def closed_box_flux(Ax, Ay, Az, half_width): return flux_x + flux_y + flux_z -# Task 9 (using the blob field Ex_b, Ey_b, Ez_b from Task 8) +# Task 9 (using the blob field Ex_b, Ey_b, Ez_b from Task 13) # 1. Finish closed_box_flux above. # 2. For h = 0.6, 1.0 and 1.4 m, print three numbers in V*m and check they # agree: the surface integral; the volume integral of div_blob over the # same cube (fw.volume_integral(div_blob[s, s, s], dx, dy, dz), with # i0, i1 = fw.box_indices(X, h)); and the enclosed charge, the volume -# integral of rho over that cube divided by epsilon_0. +# integral of rho_v over that cube divided by epsilon_0. # 3. Keep the h = 1.0 m surface integral as `flux_1m` -- the self-check # below needs that exact name. -# 4. Now settle Task 7 by measurement rather than by argument: print +# 4. Now settle Task 12 by measurement rather than by argument: print # closed_box_flux for fields (b) and (c). Both look like they are # throwing fluid outwards somewhere; a closed surface is the arbiter. @@ -781,14 +1293,14 @@ def closed_box_flux(Ax, Ay, Az, half_width): i0, i1 = fw.box_indices(X, 1.0) s = slice(i0, i1 + 1) fw.check_scalar("closed-surface flux = Q_enc/eps0", flux_1m, - fw.volume_integral(rho[s, s, s], dx, dy, dz) / epsilon_0, + fw.volume_integral(rho_v[s, s, s], dx, dy, dz) / epsilon_0, rtol=0.01, unit=" V*m") fw.check_scalar("divergence theorem: surface = volume", flux_1m, fw.volume_integral(div_blob[s, s, s], dx, dy, dz), rtol=0.01, unit=" V*m") ``` -:::{admonition} Solution — Task 9 +:::{admonition} Solution — Task 14 :class: dropdown ```python @@ -807,7 +1319,7 @@ for h in (0.6, 1.0, 1.4): s = slice(i0, i1 + 1) surf = closed_box_flux(Ex_b, Ey_b, Ez_b, h) vol = fw.volume_integral(div_blob[s, s, s], dx, dy, dz) - qenc = fw.volume_integral(rho[s, s, s], dx, dy, dz) / epsilon_0 + qenc = fw.volume_integral(rho_v[s, s, s], dx, dy, dz) / epsilon_0 print(f"{h:6.1f} {surf:12.3f} {vol:12.3f} {qenc:12.3f}") zero = np.zeros_like(X) @@ -826,32 +1338,69 @@ The number grows with $h$ and then stops: once the cube holds essentially all th ### And now shrink the source to a point -Run the same surface integral on the point-charge field from Task 4 — the one whose divergence you could never measure at the origin, because you had to mask it away. +Run the same surface integral on the point-charge field from Task 7 — the one whose divergence you could never measure at the origin, because you had to mask it away. + +Rearranged, Gauss's law turns your flux into a **charge meter**: $Q_{\text{enc}} = \varepsilon_0 \oint_S \boldsymbol{E}\cdot d\boldsymbol{s}$. So weigh the charge inside each box, in coulombs, and compare it with the 1 nC you put there. ```{code-cell} ipython3 +print("box half-width charge it finds") for h in (0.6, 1.0, 1.4): - print(f"h = {h:.1f} m : flux = {closed_box_flux(Ex, Ey, Ez, h):8.3f} V*m" - f" (Q/eps0 = {Q / epsilon_0:.3f} V*m)") - -shell = interior & (r > 0.5) & (r < 1.6) -div_point = divergence(np.nan_to_num(Ex), np.nan_to_num(Ey), np.nan_to_num(Ez), dx, dy, dz) -scale = (E_mag / Rs)[shell] # the natural size of a derivative of E here -print(f"\n|div E| away from the origin: median {np.median(np.abs(div_point[shell]) / scale):.2%} " - f"of |E|/r -- zero to within the accuracy of the grid") + Q_found = epsilon_0 * closed_box_flux(Ex, Ey, Ez, h) + print(f" {h:.1f} m {Q_found * 1e12:8.2f} pC") +print(f"\n actually there {Q * 1e12:8.2f} pC") + +# The shell between the 0.6 m and 1.4 m boxes holds no charge at all. Weigh it: +# what enters the small box must leave the large one, so the difference of the +# two fluxes is the charge in between. +Q_shell = epsilon_0 * (closed_box_flux(Ex, Ey, Ez, 1.4) + - closed_box_flux(Ex, Ey, Ez, 0.6)) +print(f"\ncharge in the shell between them: {Q_shell * 1e12:+.2f} pC " + f"({abs(Q_shell) / Q:.2%} of the charge at the centre)") ``` :::{admonition} Where did the charge go? :class: important -Every box returns $Q/\varepsilon_0$, yet the divergence is zero everywhere you can measure — *exactly* zero, by the spherical calculation above — and the boxes share nothing but the origin. +Every box weighs the same 1 nC, to a fraction of a percent — and the shell between two of them weighs nothing. All the charge is in the only region every box has in common: the origin. -So the whole source sits at one point, where $\nabla\cdot\mathbf{E}$ is not a large number but no number at all: $\rho$ has become a **Dirac delta**, zero everywhere, infinite at one point, with a finite integral $Q$. The integral form survives exactly where the differential form breaks down. +So the whole source sits at one point, where $\nabla\cdot\boldsymbol{E}$ is not a large number but no number at all: $\rho_v$ has become a **Dirac delta**, zero everywhere, infinite at one point, with a finite integral $Q$. The integral form survives exactly where the differential form breaks down. The same statement for magnetism carries no source term at all: -$$ \nabla\cdot\mathbf{B} = 0 \qquad\Longleftrightarrow\qquad \oint_S \mathbf{B}\cdot d\mathbf{s} = 0 \ \ \text{for every closed } S $$ +$$ \nabla\cdot\boldsymbol{B} = 0 \qquad\Longleftrightarrow\qquad \oint_S \boldsymbol{B}\cdot d\boldsymbol{s} = 0 \ \ \text{for every closed } S $$ + +Run this measurement around any closed surface anywhere and you get zero: there are no magnetic monopoles, and field lines of $\boldsymbol{B}$ never begin and never end. +::: + +### And the dipole, exactly + +Task 11 measured $\nabla\cdot\boldsymbol{B} = 0$ for the Earth's dipole and got 1.8% — grid error, not physics. Now make the same claim without differentiating anything: put a closed surface around the dipole and weigh what comes out. + +```{code-cell} ipython3 +r_dot_m = Z +Bx = 3*X*r_dot_m / r_safe**5 +By = 3*Y*r_dot_m / r_safe**5 +Bz = (3*Z*r_dot_m - r_safe**2) / r_safe**5 + +print(" h [m] flux of B flux of the radial flow v") +for h in (0.6, 1.0, 1.4): + f_B = closed_box_flux(*(np.nan_to_num(q) for q in (Bx, By, Bz)), h) + f_v = closed_box_flux(*(np.nan_to_num(q / r_safe**3) for q in (X, Y, Z)), h) + print(f" {h:4.1f} {f_B:+12.2e} {f_v:+12.4f}") +print(f"\n 4*pi = {4*np.pi:.4f}") + +# --- self-check (leave this alone) --- +fw.check("the dipole encloses nothing, at any radius", + max(abs(closed_box_flux(*(np.nan_to_num(q) for q in (Bx, By, Bz)), h)) + for h in (0.6, 1.0, 1.4)) < 1e-9) +``` + +:::{admonition} Two kinds of "divergence-free" +:class: important -Run this measurement around any closed surface anywhere and you get zero: there are no magnetic monopoles, and field lines of $\mathbf{B}$ never begin and never end. +The radial flow returns $4\pi$ through every surface, whatever its size — there is a tap at the origin, and every box finds the same one, exactly as every box found the same 1 nC a moment ago. + +The dipole returns **zero to machine precision**, at every radius. Not 1.8%, not small: zero. Shrink the surface as tightly as you like around the source and it stays zero, because there is no source to find. That is $\nabla\cdot\boldsymbol{B} = 0$ stated in the form that admits no exception, and it is why the integral form was worth building: it settles at the source what the differential form could only report away from it. ::: ### Where do the 1% errors come from? @@ -867,8 +1416,8 @@ for n_test in (21, 31, 41, 61): Xt, Yt, Zt = np.meshgrid(ax_t, ax_t, ax_t, indexing="ij") rt = np.sqrt(Xt**2 + Yt**2 + Zt**2) Rst = np.maximum(rt, 1e-12) - rho_t = rho0 * np.exp(-rt**2 / a**2) - E_Rt = rho0 / (epsilon_0 * Rst**2) * ( + rho_t = rho_v0 * np.exp(-rt**2 / a**2) + E_Rt = rho_v0 / (epsilon_0 * Rst**2) * ( (a**3 * np.sqrt(np.pi) / 4) * erf(Rst / a) - (a**2 * Rst / 2) * np.exp(-Rst**2 / a**2)) dv = divergence(E_Rt * Xt / Rst, E_Rt * Yt / Rst, E_Rt * Zt / Rst, h_t, h_t, h_t) @@ -885,7 +1434,7 @@ for n_test in (21, 31, 41, 61): Compare each ratio with the square of the spacing ratio — $1.5^2 = 2.25$ from $n=21$ to $31$, $1.33^2 = 1.78$ from $31$ to $41$, $1.5^2 = 2.25$ from $41$ to $61$. -So the 1.06% in Task 8 is not noise to be tolerated: it is a number you can predict, and buy down if you need to. And the choice of $n = 61$ in Part 0 is now yours to audit rather than take on trust. +So the 1.06% in Task 13 is not noise to be tolerated: it is a number you can predict, and buy down if you need to. And the choice of $n = 61$ in Part 2 is now yours to audit rather than take on trust. ::: --- @@ -894,7 +1443,7 @@ So the 1.06% in Task 8 is not noise to be tolerated: it is a number you can pred Today's chain, in one line: -$$ \rho \;\longrightarrow\; V \;\xrightarrow{\ -\nabla\ }\; \mathbf{E} \;\xrightarrow{\ \nabla\cdot\ }\; \rho/\varepsilon_0 $$ +$$ \rho_v \;\longrightarrow\; V \;\xrightarrow{\ -\nabla\ }\; \boldsymbol{E} \;\xrightarrow{\ \nabla\cdot\ }\; \rho_v/\varepsilon_0 $$ - **Gradient** — scalar in, vector out. Points along steepest increase, perpendicular to the level surfaces, with length equal to the rate of increase. - **Divergence** — vector in, scalar out. Net flux per unit volume: what is being created here, and nothing else. @@ -905,16 +1454,16 @@ Electrostatics is the convenient place to *learn* this pair, not the only place | System | Potential | Field | Source equation | | :--- | :--- | :--- | :--- | -| Electrostatics | $V$ [V] | $\mathbf{E} = -\nabla V$   [V/m] | $\nabla\cdot\mathbf{E} = \rho/\varepsilon_0$ | -| Gravitation | $\Phi$ [J/kg] | $\mathbf{g} = -\nabla \Phi$   [m/s$^2$] | $\nabla\cdot\mathbf{g} = -4\pi G\rho_m$ | -| Heat conduction | $T$ [K] | $\mathbf{q}_T = -k\nabla T$   [W/m$^2$] | $\nabla\cdot\mathbf{q}_T = 0$ (steady, no sources) | -| Groundwater flow | $h$ [m] | $\mathbf{q}_h = -K\nabla h$   [m/s] | $\nabla\cdot\mathbf{q}_h = 0$ (steady, incompressible) | +| Electrostatics | $V$ [V] | $\boldsymbol{E} = -\nabla V$   [V/m] | $\nabla\cdot\boldsymbol{E} = \rho_v/\varepsilon_0$ | +| Gravitation | $\Phi$ [J/kg] | $\boldsymbol{g} = -\nabla \Phi$   [m/s$^2$] | $\nabla\cdot\boldsymbol{g} = -4\pi G\rho_m$ | +| Heat conduction | $T$ [K] | $\boldsymbol{q}_T = -k\nabla T$   [W/m$^2$] | $\nabla\cdot\boldsymbol{q}_T = 0$ (steady, no sources) | +| Groundwater flow | $h$ [m] | $\boldsymbol{q}_h = -K\nabla h$   [m/s] | $\nabla\cdot\boldsymbol{q}_h = 0$ (steady, incompressible) | with $k$ the thermal conductivity [W m$^{-1}$ K$^{-1}$] and $K$ the hydraulic conductivity [m/s]. The minus signs are all the same minus sign: heat flows from hot to cold, water flows from high head to low, a positive charge falls from high potential to low. Flow runs downhill, and the gradient points uphill. -The last two rows are why a solenoidal field matters so much in practice. $\nabla\cdot\mathbf{q} = 0$ in an aquifer is not an approximation of convenience — it is conservation of water written locally. +The last two rows are why a solenoidal field matters so much in practice. $\nabla\cdot\boldsymbol{q} = 0$ in an aquifer is not an approximation of convenience — it is conservation of water written locally. ### What is still missing @@ -922,26 +1471,16 @@ Go back to field **(b)**, the rotation. Its divergence is zero everywhere, so by Divergence cannot see circulation. The operator that can is the **curl**, the third of the three this chapter is named after. -Keep `fwtools.py` to hand: the later labs in this chapter reuse the same helpers and the same grid conventions. - ### Homework -**Exercise A — a heat source in a room.** Replace the spherical blob with a flat rectangular heater, $1.0 \times 0.6$ m in the $z = 0$ plane. A steady point source of power $P$ in a medium of conductivity $k$ raises the temperature as $P/4\pi k R$ — the same $1/R$ you have worked with all afternoon — so superpose a $20 \times 12$ grid of them over the rectangle, exactly as you superposed two charges in Task 5: - -$$ T(\mathbf{r}) = \frac{P}{4\pi k}\sum_i \frac{\Delta A}{\lvert \mathbf{r} - \mathbf{r}_i \rvert}, \qquad k_{\text{air}} = 0.026\ \text{W m}^{-1}\text{K}^{-1} $$ - -with $P$ the total power (take 100 W) and $\Delta A$ the area each sample represents. Then: +The exercises in your lecture notes are the written homework. Below is the lab's own extension — the one piece that is computational rather than pen-and-paper, and that carries the afternoon's operators into a system you can feel. -- Plot the isosurfaces. Close to the plate they should be rounded rectangles; far away they should become spheres. Why does the shape forget its source? -- Compute the heat flux $\mathbf{q} = -k\nabla T$ — the same minus sign, the same reason. -- Check that $\nabla\cdot\mathbf{q} \approx 0$ away from the heater, and that the closed-surface flux through a box containing the plate is *not* zero. State what each result means physically for a room at steady state. - -**Exercise B — the $R^n$ family.** Using $\nabla g(R) = \dfrac{dg}{dR}\hat{\mathbf{a}}_R$, derive $|\nabla R| = 1$ and $|\nabla(1/R)| = 1/R^2$ on paper, then find which power $n$ in $R^{n}$ gives a field falling off as $1/R^{3}$. +**A heat source in a room.** Replace the spherical blob with a flat rectangular heater, $1.0 \times 0.6$ m in the $z = 0$ plane. A steady point source of power $P$ in a medium of conductivity $k$ raises the temperature as $P/4\pi k r$ — the same $1/r$ you have worked with all afternoon — so superpose a $20 \times 12$ grid of them over the rectangle, exactly as you superposed two charges in Task 8: -**Exercise C — why $1/R^2$, and not any other power.** Compute the flux of $\hat{\mathbf{a}}_R/R^{n}$ through spheres of two different radii. Show that it is independent of radius only for $n = 2$, and connect that to the fact that we live in three dimensions. This is the deepest reason Coulomb's law has the exponent it has. +$$ T(\boldsymbol{r}) = \frac{P}{4\pi k}\sum_i \frac{\Delta A}{\lvert \boldsymbol{r} - \boldsymbol{r}_i \rvert}, \qquad P = 100\ \text{W}, \qquad k_{\text{air}} = 0.026\ \text{W m}^{-1}\text{K}^{-1}, $$ -**Exercise D — the same argument in cylindrical coordinates.** An infinite line charge of density $\lambda$ on the $z$-axis produces +with $\Delta A$ the area each sample represents. Then: -$$ \mathbf{E} = \frac{\lambda}{2\pi\varepsilon_0 r}\,\hat{\mathbf{a}}_r $$ - -with $r$ now the distance from the *axis*, not the origin. Use the cylindrical divergence from the table to show $\nabla\cdot\mathbf{E} = 0$ for $r > 0$, in one line — note which power of $r$ makes $rA_r$ constant, and compare it with the $R^2E_R$ of the spherical case. Then take a cylinder of radius $r$ and length $L$ about the axis and show its flux is $\lambda L/\varepsilon_0$, independent of $r$. Why is the exponent 1 here where it was 2 before? +- Plot the isosurfaces. Close to the plate they should be rounded rectangles; far away they should become spheres. Why does the shape forget its source? +- Compute the heat flux $\boldsymbol{q}_T = -k\nabla T$ — the same minus sign, the same reason as $\boldsymbol{E} = -\nabla V$. +- Check that $\nabla\cdot\boldsymbol{q}_T \approx 0$ away from the heater, and that the closed-surface flux through a box containing the plate is *not* zero. Say what each result means physically for a room at steady state, and which of the two fields you met in Task 11 the heater resembles. From 86b76c1a908fecae52f9b519eca0123ef57b4906 Mon Sep 17 00:00:00 2001 From: ARS183 <1028762817@qq.com> Date: Tue, 1 Sep 2026 00:14:06 +0200 Subject: [PATCH 05/17] Rework the Week 1 lab after review: correct physics, given plotting, self-checks that read the blanks --- .../labs/fwtools.py | 65 +- .../labs/week01-grad-div.md | 653 ++++++++++-------- 2 files changed, 425 insertions(+), 293 deletions(-) diff --git a/book/1_gradient_divergence_curl/labs/fwtools.py b/book/1_gradient_divergence_curl/labs/fwtools.py index 93f45cd..c514f75 100644 --- a/book/1_gradient_divergence_curl/labs/fwtools.py +++ b/book/1_gradient_divergence_curl/labs/fwtools.py @@ -22,7 +22,7 @@ "z0_index", "slice_z0", "box_indices", "area_integral", "volume_integral", "show_isosurfaces", "show_cones", "show_scalar_slice", "show_field_slice", - "check", "check_shape", "check_close", "check_scalar", + "check", "check_shape", "check_close", "check_abs", "check_scalar", ] # -------------------------------------------------------------------------- @@ -119,8 +119,8 @@ def _reject_masked(F, what): def show_isosurfaces(X, Y, Z, F, levels, *, title="", label="", opacity=0.3, - colorscale="Viridis", show_caps=False, size=620, step=2, - opacity_slider=True, slice_z=None): + colorscale="Viridis", reversescale=False, show_caps=False, + size=620, step=2, opacity_slider=True, slice_z=None): """Draw one or more isosurfaces (level sets) of a scalar field F. An isosurface is the set of points where F takes one fixed value -- the @@ -142,6 +142,12 @@ def show_isosurfaces(X, Y, Z, F, levels, *, title="", label="", opacity=0.3, write ``"|\u2207r| [-]"`` and ``"[m-2]"`` with Unicode symbols -- a ``$...$`` label silently comes out as garbled glyphs. The matplotlib helpers below are the opposite: mathtext works there. + reversescale : bool + Flip the colorscale. Needed for a signed field on ``"RdBu"``: plotly + runs that scale dark *red* at the low end and dark *blue* at the high + end, the opposite of matplotlib's ``"RdBu_r"`` used by the 2-D + helpers below. Without this flag a positive lobe drawn in 3-D comes + out blue while the same lobe in the slice beside it is red. slice_z : float or None If given, also draw a filled cut plane at that value of z, exposing the interior. A strong depth cue, at the cost of hiding part of the @@ -169,7 +175,7 @@ def show_isosurfaces(X, Y, Z, F, levels, *, title="", label="", opacity=0.3, x=X.ravel(), y=Y.ravel(), z=Z.ravel(), value=np.asarray(F).ravel(), isomin=float(levels.min()), isomax=float(levels.max()), surface_count=int(levels.size), opacity=opacity, - colorscale=colorscale, showscale=True, + colorscale=colorscale, reversescale=reversescale, showscale=True, colorbar=dict(title=label, len=0.7), lighting=_LIGHTING, lightposition=_LIGHTPOSITION, caps=dict(x_show=show_caps, y_show=show_caps, z_show=show_caps), @@ -196,7 +202,8 @@ def _add_opacity_slider(fig, current): )]) -def show_cones(X, Y, Z, Ax, Ay, Az, *, step=8, title="", label="", size=620, +def show_cones(X, Y, Z, Ax, Ay, Az, *, step=8, title="", label="", unit="", + size=620, normalise=False, length=None, head=0.35, colorscale="Viridis", slider=True, width=4, log_colour=None): """Draw a 3-D vector field as arrows: a shaft with a barbed head. @@ -212,11 +219,13 @@ def show_cones(X, Y, Z, Ax, Ay, Az, *, step=8, title="", label="", size=620, Parameters ---------- - label : str - Colorbar title, e.g. ``"|E| [V/m]"``. Defaults to a generic - ``|A|``; give it the real quantity and unit so the reader can tell - the tasks apart. Plotly renders no LaTeX here -- see the note in - ``show_isosurfaces``. + label, unit : str + The plotted quantity and its unit, kept apart, e.g. + ``label="|E|", unit="V/m"``. A linear colorbar is then titled + ``|E| [V/m]``; a log one ``log10(|E| / + (V/m))``, because the logarithm of a dimensional quantity does not + carry that quantity's unit. Plotly renders no LaTeX here -- see the + note in ``show_isosurfaces``. normalise : bool Draw every arrow the same length, showing direction only. Use it for fields whose magnitude spans orders of magnitude, where true-to-scale @@ -261,9 +270,13 @@ def show_cones(X, Y, Z, Ax, Ay, Az, *, step=8, title="", label="", size=620, name = label or "|A|" if log_colour: cval = np.log10(np.maximum(mag, float(positive.min()))) - clabel = f"log10 {name}" + # log10 of a dimensional quantity is dimensionless: the unit belongs + # inside the logarithm, as a divisor, never appended in brackets. + clabel = (f"log10({name} / {unit})" if unit + else f"log10 {name}") else: - cval, clabel = mag, name + cval = mag + clabel = f"{name} [{unit}]" if unit else name px, py, pz = _arrow_lines(x, y, z, ux, uy, uz, rel * base, head) fig = go.Figure(go.Scatter3d( @@ -445,6 +458,11 @@ def show_field_slice(X, Y, Z, Ax, Ay, *, background=None, title="", label="", ``plane="z"`` cuts z = 0 and expects the (x, y) components; ``plane="y"`` cuts y = 0 and expects the (x, z) components -- pass ``Ax, Az`` there. + + Returns ``(ax, cf)``. ``cf`` is the filled-contour mappable, or ``None`` + if no background was given; pass ``colorbar=False`` on every panel of a + multi-panel figure and hand ``cf`` to ``fig.colorbar(cf, ax=axes, ...)`` + to draw a single bar spanning the lot. """ created = ax is None if created: @@ -473,7 +491,7 @@ def show_field_slice(X, Y, Z, Ax, Ay, *, background=None, title="", label="", ax.set_title(title) if colorbar and cf is not None: ax.figure.colorbar(cf, ax=ax, label=label) - return ax + return ax, cf # -------------------------------------------------------------------------- @@ -510,6 +528,27 @@ def check_close(label: str, got, want, rtol=0.05, where=None) -> None: f"np.gradient call -- did you pass dx, dy, dz, and in that order?") +def check_abs(label: str, got, atol, where=None, hint: str = "") -> None: + """Compare an array against **zero**, on an absolute scale. + + ``check_close`` divides by the expected value, so it cannot be pointed at + a quantity whose answer is exactly zero -- a solenoidal field, say. Give + this one a tolerance in the field's own units instead. ``atol`` is usually + a small fraction of the scale the field could have had: for a divergence + built from ``A ~ r`` on a grid of spacing ``dx``, anything below about + ``1e-9`` is round-off. + """ + got = np.asarray(got, float) + m = np.isfinite(got) + if where is not None: + m = m & where + if not m.any(): + raise AssertionError(f"{label} -- nothing left to compare") + worst = float(np.max(np.abs(got[m]))) + check(f"{label}: worst |value| {worst:.2e}", worst < atol, + hint or f"worst deviation from zero, {worst:.2e}, exceeds {atol:.1e}") + + def check_scalar(label: str, got: float, want: float, rtol: float = 0.01, unit: str = "") -> None: """Compare two single numbers and report the relative discrepancy.""" diff --git a/book/1_gradient_divergence_curl/labs/week01-grad-div.md b/book/1_gradient_divergence_curl/labs/week01-grad-div.md index 4ae3769..92f9a23 100644 --- a/book/1_gradient_divergence_curl/labs/week01-grad-div.md +++ b/book/1_gradient_divergence_curl/labs/week01-grad-div.md @@ -30,7 +30,7 @@ By the end of this lab you should be able to: - **Read a gradient off a picture.** Show that $\nabla r = \hat{\boldsymbol{r}}$, that $\nabla f$ is perpendicular to the level surfaces of $f$, and that $dp/dl = \lvert\nabla p\rvert\cos\psi$ — so the gradient's magnitude *is* the maximum rate of change. - **Turn a potential into a field, and a field into a survey.** Apply $\boldsymbol{E} = -\nabla V$ and Ohm's law $\boldsymbol{J} = -\rho^{-1}\nabla V$, and map the potential and current density of a two-electrode DC resistivity measurement. - **Distinguish "arrows spreading apart" from divergence.** Compute $\nabla\cdot\boldsymbol{v}$, justify the answer by flux rather than algebra, and find the only radial flow that is incompressible. -- **Use the divergence theorem as a measurement.** Verify $\oint_S\boldsymbol{v}\cdot\hat{\boldsymbol{n}}\,dS = \int_D \nabla\cdot\boldsymbol{v}\,dV$ numerically, and explain what happens when the source shrinks to a point. +- **Use the divergence theorem as a measurement.** Verify $\oint_S\boldsymbol{v}\cdot\hat{\boldsymbol{n}}\,dS = \int_{\mathcal{D}} \nabla\cdot\boldsymbol{v}\,dV$ numerically, and explain what happens when the source shrinks to a point. :::{admonition} Two sessions :class: note @@ -151,29 +151,36 @@ Now the series. The ball bounces for a total time $$ T_\infty = \sum_{m=0}^{\infty} T_m = T_0\sum_{m=0}^{\infty}\left(\sqrt{1-\gamma}\right)^{m} = \frac{\sqrt{8H/g}}{1-\sqrt{1-\gamma}}, $$ -which is a geometric series and therefore **finite** — infinitely many bounces, over in about twenty seconds. For small $\gamma$ the expansion $\sqrt{1-\gamma}\approx 1-\gamma/2$ collapses that to something much simpler, +which is a geometric series with ratio $\sqrt{1-\gamma}$. That ratio is smaller than 1 for any real bounce, so the sum is **finite** — infinitely many bounces, over in about twenty seconds. (Hold on to the condition: Task 2 is about what happens to a series when it fails.) For small $\gamma$ the expansion $\sqrt{1-\gamma}\approx 1-\gamma/2$ collapses that to something much simpler, $$ T_\infty \approx \sqrt{8H/g}\;\frac{2}{\gamma}. $$ Two questions follow, and both are worth answering by measurement rather than by intuition: **how good is that approximation**, and **how many bounces must you actually add up** before the running total gets there? ```{code-cell} ipython3 +rows = {} print(f"{'gamma':>7} {'T_inf':>9} {'approx':>9} {'error':>7} {'n for 99%':>10}") for gam in (0.5, 0.2, 0.1, 0.02): T_inf = ___ # the exact sum, from the formula above T_appr = ___ # the small-gamma approximation # --- given: how many bounces to reach 99% of T_inf --- + rows[gam] = (T_inf, T_appr) cum = np.cumsum(T0 * (1 - gam)**(np.arange(4000)/2)) n99 = int(np.argmax(cum >= 0.99*T_inf)) + 1 print(f"{gam:>7.2f} {T_inf:>8.3f}s {T_appr:>8.3f}s " f"{abs(T_appr-T_inf)/T_inf:>6.1%} {n99:>10}") # --- self-check (leave this alone) --- -_exact = np.sqrt(8*H/g) / (1 - np.sqrt(1 - 0.1)) +# Your closed form against a brute-force sum of 5000 bounces: the same +# number by two routes, one of which never assumed the series converges. _summed = np.sum(T0 * (1 - 0.1)**(np.arange(5000)/2)) -fw.check(f"the closed form ({_exact:.3f} s) equals the brute-force sum ({_summed:.3f} s)", - np.isclose(_exact, _summed, rtol=1e-6)) +fw.check(f"your T_inf at gamma = 0.1 ({rows[0.1][0]:.3f} s) equals the " + f"brute-force sum ({_summed:.3f} s)", + np.isclose(rows[0.1][0], _summed, rtol=1e-6)) +fw.check(f"your approximation overshoots by 2.6% there " + f"({rows[0.1][1]/rows[0.1][0] - 1:.2%})", + np.isclose(rows[0.1][1]/rows[0.1][0], 1.0263, rtol=1e-3)) ``` :::{admonition} Solution — Task 1, continued @@ -195,7 +202,7 @@ The term count runs the other way. The more nearly elastic the ball, the more bo ### Task 2 — where a Taylor series stops working -Any smooth function can be written as a Taylor series about $x=0$, +A function that is smooth enough — and whose series actually sums back to it, which is the catch this task is about — can be written as a Taylor series about $x=0$, $$ f(x) = f(0) + x f'(0) + \tfrac{1}{2}x^2 f''(0) + \cdots, $$ @@ -229,10 +236,10 @@ plt.tight_layout() plt.show() # --- self-check (leave this alone) --- -_s20 = sum(sin_term(m, x) for m in range(21)) +_s21 = sum(sin_term(m, x) for m in range(21)) _g_in = sum(geo_term(m, 0.5) for m in range(40)) _g_out = sum(geo_term(m, 1.5) for m in range(40)) -fw.check("20 terms reproduce sin(x) on -3 < x < 3", np.max(np.abs(_s20 - np.sin(x))) < 1e-6) +fw.check("21 terms reproduce sin(x) on -3 < x < 3", np.max(np.abs(_s21 - np.sin(x))) < 1e-6) fw.check(f"1/(1+x) converges at x = 0.5 ({_g_in:.4f} vs {1/1.5:.4f})", np.isclose(_g_in, 1/1.5)) fw.check(f"1/(1+x) diverges at x = 1.5 (partial sum {_g_out:.2e})", abs(_g_out) > 1e3) ``` @@ -256,7 +263,7 @@ def geo_term(m, x): $\sin x$ improves everywhere as you add terms. $1/(1+x)$ improves only inside $\lvert x\rvert < 1$; outside it, each extra term makes the partial sum *worse*, without limit — at $x = 1.5$ the 40-term "approximation" is off by millions. -The series has a **radius of convergence** of 1, fixed by the blow-up of $1/(1+x)$ at $x = -1$, and no amount of computing power moves it. Notice that the failure is invisible at $x = 0$: the function is perfectly smooth there, and the first few terms behave well. The limit is a property of the series, not of the point you expanded about. +The series has a **radius of convergence** of 1, and no amount of computing power moves it. What sets it is the distance from the point you expanded about to the nearest place the function blows up — here from $x=0$ to the pole at $x=-1$, one unit away. Notice that the failure is invisible at $x = 0$ itself: the function is perfectly smooth there, and the first few terms behave well. Expand the same function about $x = 1$ instead and the radius becomes 2, because the pole is now twice as far off. **The limit is set by where the function misbehaves, not by how well behaved it looks where you started.** Keep that beside Task 1. There, more terms always helped and the only question was how many. Here, more terms are useless past a certain point. Knowing which situation you are in is the whole skill. ::: @@ -296,9 +303,11 @@ print(f"X[i,j,k] = x[i] -> X[-1, 0, 0] = {X[-1, 0, 0]:.1f} m") | **61** | **0.067** | **0.8%** | **1.6%** | **1.1%** | | 81 | 0.050 | 0.5% | 1.0% | 0.6% | -Halving $\Delta x$ quarters the error, as second order requires. $n = 61$ was chosen by that measurement: it is the coarsest grid that keeps every task under 2%, and each 3-D figure it produces weighs about 1.5 MB. **If you change `n`, keep it at 41 or above** — the self-checks below allow 5%, and $n = 31$ already fails Task 6. +These are **worst cases** over the region each self-check tests, which is what fixes the tolerances — not an average. Halve $\Delta x$ and the last two columns fall by very nearly the factor of four second order promises (12.5 → 3.3, 9.1 → 2.4). The first column falls by only 2.3, and the reason is worth knowing: the $|\nabla r|$ error grows as you approach the source, so the worst sample in the band $0.4 < r < 1.6$ m is whichever one happens to sit nearest its inner edge — and *that sample moves* when you change `n`. A worst case taken over a boundary the grid keeps redrawing is not a smooth sequence. The clean demonstration is the convergence cell at the end of Part 6, which measures a fixed quantity and does recover the factor of four. -Note also that the box is a finite window on fields that extend to infinity: the largest closed surface in Part 6 sits only 0.6 m inside the outer face. +$n = 61$ was chosen by this table: it is the coarsest grid that keeps every task under 2%, and each 3-D figure it produces weighs about 1.5 MB. **If you change `n`, keep it at 41 or above** — the self-checks below allow 5%, and $n = 31$ already fails Task 6 at 6.7%. + +Two more things about this cube. It is a finite window on fields that extend to infinity: the largest closed surface in Part 6 sits only 0.6 m inside the outer face. And $z$ points **up** here, as in any ordinary right-handed frame — Part 4 works on the ground instead, and there $z$ points down into it, as Earth-science convention has it. Neither is more correct; what matters is saying which one you are in. The grid is built with `indexing='ij'`, so axis 0 is $x$, axis 1 is $y$, axis 2 is $z$. @@ -315,24 +324,31 @@ $$ r(x,y,z) = \sqrt{(x-x_0)^2 + (y-y_0)^2 + (z-z_0)^2} $$ *How far am I from that point?* One number at every location in space. No charge, no potential, no units of anything — just distance. -This is the **spherical** radial coordinate $r$ — distance from a point. The cylindrical $r$, distance from an axis, is a different quantity, and Part 4 returns to the distinction. The equations on this page use $r$; the code calls it `r`, because it is the only radius in the lab. +This is the **spherical** radial coordinate $r$ — distance from a point. The cylindrical $r$, distance from an axis, is a different quantity, and Part 5 returns to the distinction. The equations on this page use $r$; the code calls it `r`, because it is the only radius in the lab. ### Task 3 — build the distance field +**The question:** what do the surfaces of constant $r$ look like, and where do they crowd together? Answer it in your head first — this is the one field on the page you can picture completely before computing it — then build it and check. + +The source has to be movable: Task 8 puts two of them down in different places, so write the offsets in now rather than hard-coding the origin. + ```{code-cell} ipython3 # Task 3 -- distance from a source at (x0, y0, z0) to every point of the grid. def distance_to(X, Y, Z, x0=0.0, y0=0.0, z0=0.0): - return np.sqrt(___ + ___ + ___) + return ___ # root of the sum of three squares -r = distance_to(___, ___, ___) # source at the origin +r = ___ # call it: one source, at the origin # --- self-check (leave this alone) --- fw.check_shape("r", r, X.shape) fw.check("r = 0 at the origin", np.isclose(r[c, c, c], 0.0)) fw.check("r = 2 m at (2,0,0)", np.isclose(r[-1, c, c], 2.0)) fw.check("r = 2 m at (0,2,0)", np.isclose(r[c, -1, c], 2.0)) +fw.check("the source can be moved off the origin", + np.isclose(distance_to(X, Y, Z, 1.0, 0.0, 0.0)[c, c, c], 1.0), + "x0, y0, z0 have to appear in the expression -- Task 8 needs them") ``` :::{admonition} Solution — Task 3 @@ -347,7 +363,7 @@ r = distance_to(X, Y, Z) ``` ::: -A surface on which $r$ takes one fixed value is an **isosurface**, or level set — the three-dimensional version of a contour line on a map. +A surface on which $r$ takes one fixed value is an **isosurface**, or level set — the three-dimensional version of a contour line on a map. Drag the opacity slider under the figure until you can see the inner shells through the outer one. Evenly spaced values of $r$ give evenly spaced shells: the distance function has no favourite radius, which is exactly what makes its gradient so simple in the next task. ```{code-cell} ipython3 fw.show_isosurfaces(X, Y, Z, r, levels=[0.5, 1.0, 1.5], label="r [m]", @@ -380,13 +396,13 @@ rhx, rhy, rhz = X / rs, Y / rs, Z / rs # 3. Its projection onto r-hat. # 4. Draw it, then rotate the figure and compare with the spheres above. -grx, gry, grz = np.gradient(___, ___, ___, ___) +grx, gry, grz = ___ # all three spacings, in order -grad_r_mag = np.sqrt(___ + ___ + ___) +grad_r_mag = ___ # the length of that vector -radial_part = grx * ___ + gry * ___ + grz * ___ +radial_part = ___ # its projection onto (rhx, rhy, rhz) -fw.show_cones(X, Y, Z, grx, gry, grz, step=8, label="|∇r| [-]", +fw.show_cones(X, Y, Z, grx, gry, grz, step=8, label="|∇r|", unit="-", title="grad r -- unit vectors pointing away from the source") # --- self-check (leave this alone) --- @@ -394,6 +410,14 @@ band = (r > 0.4) & (r < 1.6) fw.check_shape("grad r (x-component)", grx, X.shape) fw.check_close("|grad r| = 1 everywhere", grad_r_mag, 1.0, rtol=0.05, where=band) fw.check_close("grad r is purely radial", radial_part, 1.0, rtol=0.05, where=band) +# The two checks above are the same measurement for THIS field, so they can +# only pass or fail together. This one is independent: it compares the three +# components against r-hat one at a time, so a gradient that had the right +# length but the wrong direction would be caught. +fw.check(f"grad r = r-hat, componentwise (worst " + f"{np.nanmax(np.abs(np.stack([grx-rhx, gry-rhy, grz-rhz]))[:, band]):.3f} " + f"of a unit vector)", + np.nanmax(np.abs(np.stack([grx - rhx, gry - rhy, grz - rhz]))[:, band]) < 0.05) ``` :::{admonition} Solution — Task 4 @@ -494,7 +518,7 @@ Every measured rate lies on the line. Three readings of the same picture: - **At $\cos\psi = 1$** you are walking straight up the gradient, and the rate equals $\lvert\nabla p\rvert$ exactly. Nothing beats it — that is what "steepest" means, now measured rather than asserted. - **At $\cos\psi = 0$** you are moving along the level surface and $p$ does not change at all. This is the normality result of Task 4, arriving a second time by a different route. -- **At $\cos\psi = -1$** you get $-\lvert\nabla p\rvert$: the steepest *descent*, which is the direction $\boldsymbol{E} = -\nabla V$ will pick out in Part 2. +- **At $\cos\psi = -1$** you get $-\lvert\nabla p\rvert$: the steepest *descent*, which is the direction $\boldsymbol{E} = -\nabla V$ will pick out in Part 3. One vector carries a direction *and* a rate, and the cosine tells you what you get for walking at an angle to it. ::: @@ -517,23 +541,24 @@ Same spheres as isosurfaces — $f$ is constant wherever $r$ is constant. But th r_masked = np.where(r < 0.25, np.nan, r) f = 1.0 / r_masked -# Task 6 -# 1. grad f, as components fx, fy, fz; then its magnitude f_mag. The -# self-check compares it against the predicted 1/r^2. -# 2. Draw it with normalise=True: every arrow the same length, so the -# picture shows direction only. The magnitude is not lost -- it moves -# into the colour, on a log scale (it spans three decades here). Pass -# a label so the colorbar names the quantity, e.g. -# label="|∇(1/r)| [m-2]" -- plotly colorbars take -# Unicode and a little HTML, not LaTeX. - -fx, fy, fz = ___ -f_mag = ___ +# Task 6 -- two blanks. Predict the direction before you look at the figure. +fx, fy, fz = ___ # grad f +f_mag = ___ # its magnitude, to compare with 1/r^2 +# --- given: the numbers, then the picture --- +for rr in (0.6, 1.0, 1.5): + i = int(np.argmin(np.abs(X[:, 0, 0] - rr))) + print(f"r = {rr:.1f} m : |grad f| = {f_mag[i, c, c]:8.4f} 1/r^2 = {1/rr**2:8.4f}") +# normalise=True draws every arrow the same length, so the picture carries +# direction only; the magnitude moves into the colour, on a log scale, +# because the drawn arrows span a factor of 62. +fw.show_cones(X, Y, Z, fx, fy, fz, step=8, normalise=True, + label="|∇(1/r)|", unit="m-2", + title="grad(1/r) -- pointing back towards the source") # --- self-check (leave this alone) --- -outside = (r > 0.5) & interior # `interior` was built in Part 0 +outside = (r > 0.5) & interior # `interior` was built in Part 2 fw.check_close("|grad(1/r)| = 1/r^2", f_mag, 1.0 / r_masked**2, rtol=0.05, where=outside) fw.check("grad(1/r) points inward at (1,0,0)", fx[-1 - 15, c, c] < 0) ``` @@ -544,14 +569,6 @@ fw.check("grad(1/r) points inward at (1,0,0)", fx[-1 - 15, c, c] < 0) ```python fx, fy, fz = np.gradient(f, dx, dy, dz) f_mag = np.sqrt(fx**2 + fy**2 + fz**2) - -for rr in (0.6, 1.0, 1.5): - i = int(np.argmin(np.abs(X[:, 0, 0] - rr))) - print(f"r = {rr:.1f} m : |grad f| = {f_mag[i, c, c]:8.4f} 1/r^2 = {1/rr**2:8.4f}") - -fw.show_cones(X, Y, Z, fx, fy, fz, step=8, normalise=True, - label="|∇(1/r)| [m-2]", - title="grad(1/r) -- pointing back towards the source") ``` ::: @@ -582,15 +599,19 @@ You already know what $\nabla V$ does: it points inward, uphill towards the char ```{code-cell} ipython3 V = k_e * Q / r_masked -# Task 7 -# 1. E = -grad V, as components Ex, Ey, Ez; then E_mag. -# 2. Compare E_mag against the analytic k_e*Q/r^2 at a few radii, in V/m. -# 3. Draw it with normalise=True and confirm it points OUTWARD for Q > 0. - -Ex, Ey, Ez = ___ +# Task 7 -- two blanks. Mind the minus sign; it is the whole task. +Ex, Ey, Ez = ___ # E = -grad V E_mag = ___ +# --- given: against the analytic k_e*Q/r^2, then the picture --- +for rr in (0.6, 1.0, 1.5): + i = int(np.argmin(np.abs(X[:, 0, 0] - rr))) + print(f"r = {rr:.1f} m : |E| = {E_mag[i, c, c]:8.3f} V/m " + f"analytic = {k_e*Q/rr**2:8.3f} V/m") +fw.show_cones(X, Y, Z, Ex, Ey, Ez, step=8, normalise=True, + label="|E|", unit="V/m", + title="E = -grad V for a positive point charge") # --- self-check (leave this alone) --- fw.check_close("|E| = Q/(4 pi eps0 r^2)", E_mag, k_e * Q / r_masked**2, @@ -605,15 +626,6 @@ fw.check("E points outward at (1,0,0)", Ex[-1 - 15, c, c] > 0) dVdx, dVdy, dVdz = np.gradient(V, dx, dy, dz) Ex, Ey, Ez = -dVdx, -dVdy, -dVdz E_mag = np.sqrt(Ex**2 + Ey**2 + Ez**2) - -for rr in (0.6, 1.0, 1.5): - i = int(np.argmin(np.abs(X[:, 0, 0] - rr))) - print(f"r = {rr:.1f} m : |E| = {E_mag[i, c, c]:8.3f} V/m " - f"analytic = {k_e*Q/rr**2:8.3f} V/m") - -fw.show_cones(X, Y, Z, Ex, Ey, Ez, step=8, normalise=True, - label="|E| [V/m]", - title="E = -grad V for a positive point charge") ``` ::: @@ -622,7 +634,7 @@ fw.show_cones(X, Y, Z, Ex, Ey, Ez, step=8, normalise=True, $V$ is a scalar: one number per point, no direction to keep track of. $\boldsymbol{E}$ is a vector: three. Anything you can do once on $V$ and then differentiate is cheaper — in arithmetic and in bookkeeping — than doing it three times on $\boldsymbol{E}$. -Part 3 is the first payoff, and it is the reason the potential is worth defining in the first place. +Part 4 is the first payoff, and it is the reason the potential is worth defining in the first place. ::: --- @@ -640,35 +652,33 @@ Since $\nabla$ is a linear operator, $-\nabla(V_1 + V_2) = \boldsymbol{E}_1 + \b ### Task 8 — build a dipole ```{code-cell} ipython3 -# Distances to two sources on the x-axis. The guard only trips if a grid -# point lands exactly on a charge; at n = 61 none does, so nothing is masked -# here and you see the full field. Raise it if you change the grid. -r_plus = np.where(distance_to(X, Y, Z, -0.5, 0.0, 0.0) < 0.01, np.nan, - distance_to(X, Y, Z, -0.5, 0.0, 0.0)) -r_minus = np.where(distance_to(X, Y, Z, +0.5, 0.0, 0.0) < 0.01, np.nan, - distance_to(X, Y, Z, +0.5, 0.0, 0.0)) - -# Task 8 -# 1. Superpose the potentials of +Q at (-0.5, 0, 0) and -Q at (+0.5, 0, 0) -# into V_dip. Scalar addition -- just a sum. -# 2. Take ONE gradient, negate it: Ex_d, Ey_d, Ez_d. -# 3. Draw the z = 0 plane, potential as colour and field as streamlines -# (replace ... with a title of your own): -# fw.show_field_slice(X, Y, Z, Ex_d, Ey_d, background=V_dip, -# title=..., label="$V$ [V]") -# then plt.show(). - -V_dip = ___ -Ex_d, Ey_d, Ez_d = ___ - - +# Distances to the two charges. +Q sits at x = +d/2, -Q at x = -d/2 -- the +# same placement Task 9 will give the current source and sink, so the two +# pictures can be laid side by side. The guard only trips if a grid point +# lands exactly on a charge; at n = 61 none does, so nothing is masked here +# and you see the full field. Raise it if you change the grid. +d_sep = 1.0 # charge separation [m] +r_plus = np.where(distance_to(X, Y, Z, +d_sep/2, 0.0, 0.0) < 0.01, np.nan, + distance_to(X, Y, Z, +d_sep/2, 0.0, 0.0)) +r_minus = np.where(distance_to(X, Y, Z, -d_sep/2, 0.0, 0.0) < 0.01, np.nan, + distance_to(X, Y, Z, -d_sep/2, 0.0, 0.0)) + +# Task 8 -- two blanks. +V_dip = ___ # superpose: +Q over r_plus, -Q over r_minus +Ex_d, Ey_d, Ez_d = ___ # ONE gradient of the sum, negated + +# --- given: the z = 0 plane, potential as colour, field as streamlines --- +fw.show_field_slice(X, Y, Z, Ex_d, Ey_d, background=V_dip, + title="Source and sink: potential (colour) and field lines", + label="$V$ [V]") +plt.show() # --- self-check (leave this alone) --- mid = np.abs(X) < 1e-9 # the plane x = 0, halfway between them fw.check_shape("V_dip", V_dip, X.shape) fw.check("V = 0 on the mid-plane", np.nanmax(np.abs(V_dip[mid])) < 1e-6 * np.nanmax(np.abs(V_dip))) -fw.check("E on the mid-plane points from + to -", np.nanmean(Ex_d[mid]) > 0) +fw.check("E on the mid-plane points from + to -", np.nanmean(Ex_d[mid]) < 0) ``` :::{admonition} Solution — Task 8 @@ -679,28 +689,68 @@ V_dip = k_e * Q / r_plus + k_e * (-Q) / r_minus dVx, dVy, dVz = np.gradient(V_dip, dx, dy, dz) Ex_d, Ey_d, Ez_d = -dVx, -dVy, -dVz - -fw.show_field_slice(X, Y, Z, Ex_d, Ey_d, background=V_dip, - title="Source and sink: potential (colour) and field lines", - label="$V$ [V]") -plt.show() ``` ::: :::{admonition} Look at the mid-plane before you move on :class: tip -At $x = 0$, the potential is **exactly zero**. Yet the field there is not zero at all: it is at its strongest, pointing straight from the positive charge to the negative one. +At $x = 0$, the potential is **exactly zero**. Yet the field there is not zero at all: it is at its strongest, pointing straight from the positive charge to the negative one — here in the $-\hat{\boldsymbol{x}}$ direction, since $+Q$ sits on the right. The field is the *slope* of the potential, not its value. A landscape can be at sea level and still be steep. Notice also what the picture shows about direction: the streamlines cross the coloured contours at right angles everywhere, which is Task 4's normality result showing up in a field you did not construct radially. ::: +### Far away, it is one object + +Now the connection back to Part 1. Nothing about $V_{\text{dip}}$ is a series — it is two exact terms. But step far enough back and the two charges stop being resolvable, and what survives is a **truncation**. + +Expand $1/r_\pm$ in powers of $d/r$ and add. The two leading terms are equal and opposite — the charges cancel, as they must, since the pair carries no net charge — and the first thing left is + +$$ V \;\approx\; \frac{1}{4\pi\varepsilon_0}\frac{\boldsymbol{p}\cdot\hat{\boldsymbol{r}}}{r^{2}}, \qquad \boldsymbol{p} = Q d\,\hat{\boldsymbol{x}}, $$ + +the **dipole moment** $\boldsymbol{p}$ pointing from the negative charge to the positive one. Everything dropped is smaller by a further factor of $(d/r)^2$ — so this is Task 1's question again, asked of space instead of time: *how far away do you have to stand before one term is enough?* + +```{code-cell} ipython3 +# --- given: exact against the one-term far field, along the +x axis --- +p_mom = Q * d_sep # dipole moment [C m] +r_ff = np.logspace(np.log10(0.8), np.log10(60), 2000) +V_ex = k_e * Q * (1/np.abs(r_ff - d_sep/2) - 1/np.abs(r_ff + d_sep/2)) +V_ff = k_e * p_mom / r_ff**2 # p . r-hat = p on the axis +err_ff = np.abs(V_ff - V_ex) / np.abs(V_ex) + +plt.figure(figsize=(5.8, 4.2)) +plt.loglog(r_ff / d_sep, err_ff, "k", lw=1.6) +for tol, colour in ((0.10, "C1"), (0.01, "C2"), (0.001, "C3")): + r_ok = r_ff[np.argmax(err_ff < tol)] / d_sep + plt.axhline(tol, color=colour, lw=0.8, ls=":") + plt.plot([r_ok], [tol], "o", color=colour, ms=5) + print(f" one term is good to {tol:6.1%} beyond r = {r_ok:5.1f} separations") +plt.xlabel("$r$ / separation $d$"); plt.ylabel("relative error of the one-term form") +plt.grid(alpha=0.3, which="both"); plt.title("How far is far?") +plt.show() + +# --- self-check (leave this alone) --- +fw.check("the far-field error falls as (d/r)^2", + np.isclose(np.polyfit(np.log(r_ff[r_ff > 10]), np.log(err_ff[r_ff > 10]), 1)[0], + -2.0, atol=0.05)) +``` + +:::{admonition} The same question as the bouncing ball +:class: important + +Two decades of accuracy cost about a factor of ten in distance: good to 10% at $1.6\,d$, to 1% at $5\,d$, to 0.1% at $16\,d$. That is the $(d/r)^2$ law, and $\sqrt{10} \approx 3.2$ is the factor between each pair. + +Compare it with Task 1. There, "how many terms for 1%?" had the answer 88, and it grew as the ball became more elastic. Here the knob is not a term count but a *distance*, and the answer grows the closer you stand. In both cases the truncation is only as good as the regime, and in both cases you can find out which regime you are in by measuring rather than hoping. + +This one term is why a compass works. A magnet has a complicated field close up; a metre away it is a dipole and nothing else, which is exactly why the Earth's field is worth writing as the single term you will meet in Task 11. +::: + The same object in three dimensions — positive and negative equipotential surfaces together, drawn transparent: ```{code-cell} ipython3 lobe = np.nanpercentile(np.abs(V_dip), 97) fw.show_isosurfaces(X, Y, Z, np.nan_to_num(V_dip), levels=[-lobe, -lobe/3, lobe/3, lobe], - colorscale="RdBu", opacity=0.3, label="V [V]", + colorscale="RdBu", reversescale=True, opacity=0.3, label="V [V]", title="Equipotential surfaces of a dipole") ``` @@ -724,42 +774,54 @@ This is a real measurement — a DC resistivity survey, the workhorse of near-su In this task $\rho$ is the **electrical resistivity** in Ω·m. In Task 13 it will be a charge density in C/m³, written $\rho_v$ to keep them apart. The symbol is overloaded across the whole subject; the units tell you which is which. ::: -The ground is a half-space, so this needs its own grid: $x$ and $y$ still run $-L$ to $L$, but $z$ runs from $0$ (the surface) downwards. +The ground is a half-space, so this needs its own grid: $x$ and $y$ still run $-L$ to $L$, but $z$ runs from $0$ (the surface) **downwards**, the Earth-science convention. + +A real electrode is a metal stake, not a mathematical point: a conductor of some finite radius $r_{\text{el}}$, held at one potential over its whole surface. Model it that way — floor the distance at $r_{\text{el}}$ — and $1/r$ never blows up. Nothing is masked, no sample is thrown away, and every derivative below is taken on a field that is finite everywhere. ```{code-cell} ipython3 rho, I, a_sep = 100.0, 1.0, 1.0 # ohm.m, ampere, electrode spacing [m] +r_el = 0.12 # electrode radius [m] -axis_g = np.linspace(-2.0, 2.0, 81) # x and y -depth = np.linspace(0.0, 2.0, 41) # z, into the ground +axis_g = np.linspace(-2.0, 2.0, 81) # x and y, across the survey line +depth = np.linspace(0.0, 2.0, 51) # z, down into the ground Xg, Yg, Zg = np.meshgrid(axis_g, axis_g, depth, indexing="ij") dxg = axis_g[1] - axis_g[0] dzg = depth[1] - depth[0] +print(f"dxg = {dxg:.3f} m, dzg = {dzg:.3f} m <- deliberately not equal") def dist_to(x0): - return np.sqrt((Xg - x0)**2 + Yg**2 + Zg**2) - -# Task 9 -# 1. V from the formula above: source at x = +a_sep/2, sink at x = -a_sep/2. -# Mask each distance below 0.12 m -- the electrodes are singular points. -# 2. J = -grad(V)/rho, as Jx, Jy, Jz. Pass dxg, dxg, dzg -- z is spaced -# differently from x and y on this grid. -# 3. Two panels, stacked: -# fig, axes = plt.subplots(2, 1, figsize=(7.5, 9)) -# fw.show_field_slice(Xg, Yg, Zg, Jx, Jy, background=V_dc, ax=axes[0], -# plane="z", label="$V$ [V]", title=...) -# fw.show_field_slice(Xg, Yg, Zg, Jx, Jz, background=V_dc, ax=axes[1], -# plane="y", label="$V$ [V]", title=...) -# plane="z" is the ground surface; plane="y" is the vertical section, -# and there the in-plane components are (Jx, Jz), not (Jx, Jy). -# Finish with axes[1].invert_yaxis() so depth runs downwards. + """Distance to an electrode at (x0, 0, 0), floored at its own radius.""" + return np.maximum(np.sqrt((Xg - x0)**2 + Yg**2 + Zg**2), r_el) + +# Task 9 -- two blanks. This is Task 8 again, in different clothes. +# V: the formula above, source at x = +a_sep/2, sink at x = -a_sep/2. +# dist_to floors the distance at the electrode radius, so there is +# nothing to mask and nothing to nan_to_num. +# J: -grad(V)/rho. Pass dxg, dxg, dzg. On this grid z really is spaced +# differently from x and y, and passing dxg three times costs 6.5% on +# the current measured in the next cell -- enough to fail its check. V_dc = ___ Jx, Jy, Jz = ___ - +# --- given: the survey, both panels on one colour scale and one colorbar --- +# plane="z" is the ground surface; plane="y" is the vertical section, where +# the in-plane components are (Jx, Jz), not (Jx, Jy). +vm = float(np.nanpercentile(np.abs(V_dc[:, :, 0]), 98)) +fig, axes = plt.subplots(2, 1, figsize=(7.2, 9.2)) +for ax_, comps, pl, ttl in ((axes[0], (Jx, Jy), "z", "a) ground surface, $z=0$"), + (axes[1], (Jx, Jz), "y", "b) vertical section, $y=0$")): + _, cf = fw.show_field_slice(Xg, Yg, Zg, *comps, background=V_dc, ax=ax_, + plane=pl, vmin=-vm, vmax=vm, colorbar=False, + density=1.2, title=ttl) +axes[1].invert_yaxis() # depth increases downwards +fig.colorbar(cf, ax=axes, label="$V$ [V]", fraction=0.05, pad=0.03) +plt.show() # --- self-check (leave this alone) --- mid_dc = np.abs(Xg) < 1e-9 +fw.check("V is finite everywhere -- no holes in the model", + np.all(np.isfinite(V_dc)) and np.all(np.isfinite(Jx))) fw.check("V = 0 on the mid-plane between the electrodes", np.nanmax(np.abs(V_dc[mid_dc])) < 1e-6 * np.nanmax(np.abs(V_dc))) fw.check("current flows from the source towards the sink at the surface", @@ -770,23 +832,13 @@ fw.check("current flows from the source towards the sink at the surface", :class: dropdown ```python -guard = 0.12 -d_src = np.where(dist_to(+a_sep/2) < guard, np.nan, dist_to(+a_sep/2)) -d_snk = np.where(dist_to(-a_sep/2) < guard, np.nan, dist_to(-a_sep/2)) -V_dc = rho * I / (2*np.pi) * (1/d_src - 1/d_snk) +V_dc = rho * I / (2*np.pi) * (1/dist_to(+a_sep/2) - 1/dist_to(-a_sep/2)) -gVx, gVy, gVz = np.gradient(np.nan_to_num(V_dc), dxg, dxg, dzg) +gVx, gVy, gVz = np.gradient(V_dc, dxg, dxg, dzg) Jx, Jy, Jz = -gVx/rho, -gVy/rho, -gVz/rho - -fig, axes = plt.subplots(2, 1, figsize=(7.5, 9)) -for ax_, comps, pl, ttl in ((axes[0], (Jx, Jy), "z", "a) ground surface, $z=0$"), - (axes[1], (Jx, Jz), "y", "b) vertical section, $y=0$")): - fw.show_field_slice(Xg, Yg, Zg, *comps, background=V_dc, ax=ax_, plane=pl, - label="$V$ [V]", density=1.2, title=ttl) -axes[1].invert_yaxis() # depth increases downwards -plt.tight_layout() -plt.show() ``` + +One presentation point worth stealing for your own figures: `show_field_slice` returns `(ax, cf)`, so passing `colorbar=False` on both panels and handing the mappable `cf` to `fig.colorbar(..., ax=axes)` draws **one** bar beside the pair. Two bars carrying identical numbers is clutter, and it invites the reader to think the scales differ. ::: Now use the field as an instrument. *All* the current injected at one electrode has to cross any closed surface you draw around it — there is nowhere else for it to go. Test that. @@ -820,7 +872,7 @@ fw.check_scalar("box around the sink carries -I", buried_box_current(-a_sep/2), The box is closed by the ground surface itself. Air does not conduct, so $J_z = 0$ at $z=0$ — a **boundary condition**, true by physics, not something to be measured. -It is worth seeing what happens if you do try to measure it. `np.gradient` has no neighbour above $z=0$, so it falls back to a one-sided difference there, right beside a singular electrode — and reports about $-0.35$ A of current flowing into the sky. Including that face would corrupt a result that is otherwise good to 0.35%. +It is worth seeing what happens if you do try to measure it. `np.gradient` has no neighbour above $z=0$, so it falls back to a one-sided difference there — and reports a spurious $J_z$ averaging $+0.25$ A/m² over the top of the box, current apparently sinking in from the air. The outward normal on that face is $-\hat{\boldsymbol{z}}$, so it enters the sum as $-0.088$ A and drags the box from $1.003$ A down to $0.915$ A: an **8.5% error**, on a result that is otherwise good to 0.3%. The lesson generalises well beyond this lab: **where you know a boundary condition exactly, impose it — do not ask a finite-difference stencil to rediscover it.** Numerical derivatives are least trustworthy exactly where your domain stops. ::: @@ -839,7 +891,7 @@ Parts 1–4 are the gradient, and that is where the first afternoon ends. **Part The gradient took a scalar and returned a vector. The divergence goes the other way — hand it a vector field, get back a scalar: -$$ \nabla\cdot\boldsymbol{A} \;=\; \lim_{\Delta v \to 0}\frac{1}{\Delta v}\oint_S \boldsymbol{A}\cdot d\boldsymbol{s} \;=\; \frac{\partial A_x}{\partial x} + \frac{\partial A_y}{\partial y} + \frac{\partial A_z}{\partial z} $$ +$$ \nabla\cdot\boldsymbol{A} \;=\; \lim_{\Delta V \to 0}\frac{1}{\Delta V}\oint_S \boldsymbol{A}\cdot\hat{\boldsymbol{n}}\,dS \;=\; \frac{\partial A_x}{\partial x} + \frac{\partial A_y}{\partial y} + \frac{\partial A_z}{\partial z} $$ Read the definition on the left, not the formula on the right: **treat $\boldsymbol{A}$ as the velocity of a fluid**, put a small box anywhere, and measure the net outflow through its walls per unit volume. @@ -849,38 +901,50 @@ Read the definition on the left, not the formula on the right: **treat $\boldsym | $< 0$ | **sink** | a drain — more arrives than leaves | | $= 0$ | **solenoidal** | whatever flows in, flows out | -### Task 10 — write the divergence +### Task 10 — the operator, and where it is measured from -```{code-cell} ipython3 -# Task 10 -# Write divergence(Ax, Ay, Az, dx, dy, dz) returning -# dAx/dx + dAy/dy + dAz/dz -- one derivative along one axis per component. -# np.gradient(Ax, dx, axis=0) gives dAx/dx and nothing else; asking it for -# all three and throwing two away costs three times the memory, which -# matters in the browser. The cross terms are not part of a divergence. +The operator itself is three lines, and you are given them. One derivative along one axis per component: `np.gradient(Ax, dx, axis=0)` returns $\partial A_x/\partial x$ and nothing else, where asking for all three and discarding two would cost three times the memory. The cross terms are not part of a divergence. -# Write your code here: +**The question is the one the definition raises.** Flux per unit volume is measured around *a point* — so does the answer depend on which point you call the origin? Take the outward flow $\boldsymbol{A} = \boldsymbol{r}$, whose divergence you can do on paper: $1+1+1 = 3$. Now shift the whole field so it streams out of $(0.8, -0.4, 0.3)$ instead. Predict the divergence before you compute it. +```{code-cell} ipython3 +# --- given --- +def divergence(Ax, Ay, Az, dx, dy, dz): + return (np.gradient(Ax, dx, axis=0) + + np.gradient(Ay, dy, axis=1) + + np.gradient(Az, dz, axis=2)) +# Task 10 -- two blanks. The same outward flow, seen from somewhere else. +x0, y0, z0 = 0.8, -0.4, 0.3 +Sx, Sy, Sz = ___ # the field r - r0, as three arrays +div_shifted = ___ # its divergence # --- self-check (leave this alone) --- -# The position vector A = x a_x + y a_y + z a_z has divergence 1 + 1 + 1 = 3 -# everywhere. Confirm that on paper before you trust the number. fw.check_close("div of the position vector = 3", divergence(X, Y, Z, dx, dy, dz), 3.0, rtol=1e-6) +fw.check_close("...and 3 again when the source is moved", + div_shifted, 3.0, rtol=1e-6) +fw.check("the shifted field really is different from the original", + not np.allclose(Sx, X)) ``` :::{admonition} Solution — Task 10 :class: dropdown ```python -def divergence(Ax, Ay, Az, dx, dy, dz): - return (np.gradient(Ax, dx, axis=0) - + np.gradient(Ay, dy, axis=1) - + np.gradient(Az, dz, axis=2)) +Sx, Sy, Sz = X - x0, Y - y0, Z - z0 +div_shifted = divergence(Sx, Sy, Sz, dx, dy, dz) ``` ::: +:::{admonition} Why it had to be 3 either way +:class: tip + +Moving the source changed every arrow in the box, and changed the divergence nowhere. Differentiation kills the constant: $\partial(x - x_0)/\partial x = 1$ whatever $x_0$ is. + +That is worth more than it looks. The divergence is a **local** quantity — it is built from a limit taken around one point, so it can only know about the field in a shrinking neighbourhood of that point, and nothing about where you chose to put your axes. Every operator in this course has that property, and it is what lets you write $\nabla\cdot\boldsymbol{E} = \rho_v/\varepsilon_0$ as a statement about *places* rather than about coordinate systems. +::: + ### Task 11 — the only incompressible radial flow A first use of the operator. Water of constant density flows outward from a source at the origin. Away from that source nothing is created or destroyed, so the flow must be **incompressible**: @@ -894,50 +958,61 @@ $$ \nabla\cdot\boldsymbol{v} = 3f(r) + r\frac{df}{dr} = 0 \qquad\Longrightarrow\ Do not take that on trust — find it. Try four candidates and let the divergence pick. ```{code-cell} ipython3 -# Task 11 -# For f(r) = const, 1/r^2, 1/r^3, 1/r^4, build v = f(r) * (X, Y, Z) using -# r_safe below, take the divergence, and report a scale-free measure of how -# far each is from zero: median |div v| / median(|v|/r) over the test band. -# Only one candidate should come out near zero. +# The measure to report, once, so the loop below reads as physics: +# +# |div v| / (|v| / r), median over the test band +# +# |v|/r is the natural size of a derivative of v, so the ratio is a pure +# number -- 1 means "as large as a derivative of this field could be". r_safe = np.where(r < 0.3, np.nan, r) band_i = interior & (r > 0.6) & (r < 1.6) +# Task 11 -- three blanks, inside the loop. +results = {} for name, f_r in [("const", np.ones_like(r_safe)), ("1/r^2", 1/r_safe**2), ("1/r^3", 1/r_safe**3), ("1/r^4", 1/r_safe**4)]: - pass # replace this loop body with your own - + vx, vy, vz = ___ # v = f(r) * (X, Y, Z): three arrays + dv = ___ # its divergence (nan_to_num each part) + scale = ___ # |v|/r AT THE BAND POINTS -- index it + # with [band_i], so it comes out 1-D + # and the same length as dv[band_i] + # --- given --- + results[name] = np.nanmedian(np.abs(dv[band_i]) / scale) + print(f" f = {name:6s}: median |div v| / (|v|/r) = {results[name]:8.2%}") # --- self-check (leave this alone) --- -_v = 1/r_safe**3 -_d = divergence(*(np.nan_to_num(_v*q) for q in (X, Y, Z)), dx, dy, dz) -_scale = np.nanmedian(np.abs(np.sqrt(3)*_v*r_safe/r_safe)[band_i]) -fw.check("1/r^3 is the divergence-free one", - np.nanmedian(np.abs(_d[band_i])) / _scale < 0.05) +fw.check(f"scale is one value per band point ({np.shape(scale)} vs " + f"{np.shape(dv[band_i])})", np.shape(scale) == np.shape(dv[band_i]), + "index it with [band_i] -- a whole-grid array or a single median " + "both change the statistic being reported") +fw.check(f"1/r^3 is the divergence-free one ({results['1/r^3']:.2%})", + results["1/r^3"] < 0.05) +fw.check("...and the other three are not", + min(results[k] for k in ("const", "1/r^2", "1/r^4")) > 0.5) +fw.check(f"f = const reproduces Task 10's div(r) = 3 ({results['const']:.2%})", + np.isclose(results["const"], 3.0, rtol=1e-3)) ``` :::{admonition} Solution — Task 11 :class: dropdown ```python -for name, f_r in [("const", np.ones_like(r_safe)), - ("1/r^2", 1/r_safe**2), - ("1/r^3", 1/r_safe**3), - ("1/r^4", 1/r_safe**4)]: vx, vy, vz = f_r*X, f_r*Y, f_r*Z - d = divergence(np.nan_to_num(vx), np.nan_to_num(vy), np.nan_to_num(vz), dx, dy, dz) - scale = np.nanmedian((np.sqrt(vx**2 + vy**2 + vz**2) / r_safe)[band_i]) - print(f" f = {name:6s}: median |div v| / (|v|/r) = {np.nanmedian(np.abs(d[band_i]))/scale:8.2%}") + dv = divergence(*(np.nan_to_num(q) for q in (vx, vy, vz)), dx, dy, dz) + scale = (np.sqrt(vx**2 + vy**2 + vz**2) / r_safe)[band_i] ``` ::: :::{admonition} Where the inverse-square law comes from :class: important -Three candidates sit near 100%; one sits under 1%. Only $f = A/r^{3}$ survives, exactly as the algebra says — and note what that means for the field itself: +One candidate sits at 300%, two at almost exactly 100%, and one at 0.66%. Only $f = A/r^{3}$ survives, exactly as the algebra says. + +The 300% is not an accident, and it is worth recognising: for $f = \text{const}$ the field *is* the position vector, $\boldsymbol{v} = \boldsymbol{r}$, whose divergence you measured in Task 10 as exactly 3 — while $\lvert\boldsymbol{v}\rvert/r = 1$, so the ratio has to be 3. Note also what the surviving case means for the field itself: $$ \boldsymbol{v} = \frac{A}{r^{3}}\boldsymbol{r} = \frac{A}{r^{2}}\,\hat{\boldsymbol{r}}. $$ @@ -950,11 +1025,13 @@ Coulomb's law, Newton's gravity and this water all share an exponent for that on Notice the small print on that result: $\nabla\cdot\boldsymbol{v} = 0$ **for $r \neq 0$**. The origin is excluded, and it has to be — that is where the water is injected. Put a closed surface around it and you would find the tap. -Now a field with no such exception. To first order the Earth's magnetic field is a **dipole**: a north and a south pole so close together that they coincide. With dipole moment $\boldsymbol{m}$ pointing from south to north, +Now a field with no such exception. To first order the Earth's magnetic field is a **dipole**: a north and a south pole so close together that they coincide. With dipole moment $\boldsymbol{m}$, $$ \boldsymbol{B} = \frac{3\boldsymbol{r}\,(\boldsymbol{r}\cdot\boldsymbol{m}) - r^{2}\boldsymbol{m}}{r^{5}}. $$ -Take $\boldsymbol{m} = \hat{\boldsymbol{z}}$ and measure its divergence with the same function. +Take $\boldsymbol{m} = \hat{\boldsymbol{z}}$ on the cube of Part 2, where $z$ points up, and measure the divergence with the same function. + +(The Earth's own moment points roughly geographic *south*, which is why the magnetic pole in the Arctic is magnetically a **south** pole and pulls the north end of a compass needle towards it. Reversing $\boldsymbol{m}$ reverses every arrow below and changes nothing at all about $\nabla\cdot\boldsymbol{B}$, which is the point of the task.) ```{code-cell} ipython3 # Task 11, continued -- fill in the three components. @@ -997,7 +1074,7 @@ Both fields are divergence-free where you measured, but they are not the same st The water needed an exclusion: $\nabla\cdot\boldsymbol{v} = 0$ *away from the origin*, because the origin is a tap. The dipole needs none — $\nabla\cdot\boldsymbol{B} = 0$ holds **everywhere in space, including at the source itself**. There is no point you could exclude and find a magnet leaking field the way the tap leaks water. That is one of Maxwell's equations, and it says magnetic monopoles do not exist: field lines of $\boldsymbol{B}$ never begin and never end, they only close on themselves. -Two footnotes on the numbers. The dipole's median error, near 1.8%, is worse than the radial flow's 0.7% — not because the physics is shakier but because $\boldsymbol{B}$ falls off as $1/r^{3}$ instead of $1/r^{2}$, so a centred difference has more curvature to miss. Part 6 will make the "no exception" claim exactly rather than to 2%, by putting a closed surface around the dipole instead of differentiating it. +Two footnotes on the numbers. Both cells report the same scale-free measure, so the numbers are directly comparable: the dipole's 1.8% is worse than the radial flow's 0.66% — not because the physics is shakier but because $\boldsymbol{B}$ falls off as $1/r^{3}$ instead of $1/r^{2}$, so a centred difference has more curvature to miss. Part 6 pushes the "no exception" claim far below that 2%, by putting a closed surface around the dipole instead of differentiating it. And the second check is worth a moment: $\boldsymbol{B}\cdot\boldsymbol{r}$ goes negative somewhere, which the outward flow of Task 11 never does. The dipole points *inward* over part of space — it returns. That is what "closes on itself" looks like in a number. ::: @@ -1019,29 +1096,40 @@ predictions = {"a": ___, "b": ___, "c": ___} ``` ```{code-cell} ipython3 -# Task 12 -# 1. Build the three fields as triples of arrays. -# 2. Take the divergence of each with your Task 10 function, as div_a, -# div_b and div_c -- the self-check needs those names. Print the mean -# of each. -# 3. Draw fields (a) and (c) side by side in the z = 0 plane, streamlines -# over their own divergence as the background, both on the SAME scale -# so the colours are comparable: -# fig, axes = plt.subplots(1, 2, figsize=(12, 4.6)) -# fw.show_field_slice(X, Y, Z, *Aa[:2], background=div_a, ax=axes[0], -# vmin=-3, vmax=3, label=r"$\nabla\cdot\boldsymbol{A}$", -# title="(a) outward flow") -# ... and the same for (c) with Ac and div_c. -# Look hard at the two before reading the note below. +# Task 12 -- six blanks: three fields, three divergences. +zero = np.zeros_like(X) +Aa = ___ # (a) outward flow, as a triple +Ab = ___ # (b) rotation about z +Ac = ___ # (c) stretch in x, squeeze in y -# Write your code here: +div_a = ___ +div_b = ___ +div_c = ___ +# --- given: the three side by side, one shared scale, one colorbar --- +for name, d in [("(a) outward flow", div_a), ("(b) rotation", div_b), + ("(c) shear", div_c)]: + print(f"{name:20s} div = {d.mean():+.3f}") +fig, axes = plt.subplots(1, 3, figsize=(16, 4.6)) +for ax_, (name, A, d) in zip(axes, [("(a) outward flow", Aa, div_a), + ("(b) rotation", Ab, div_b), + ("(c) shear flow", Ac, div_c)]): + fw.show_field_slice(X, Y, Z, *A[:2], background=d, ax=ax_, density=1.1, + vmin=-3, vmax=3, colorbar=(ax_ is axes[-1]), + label=r"$\nabla\cdot\boldsymbol{A}$ [s$^{-1}$]", title=name) +plt.tight_layout() +plt.show() +# Look hard at (b) and (c) before reading the note below: both come out a +# uniform zero, and they get there for completely different reasons. # --- self-check (leave this alone) --- +# (a) has a non-zero answer, so a relative test works. (b) and (c) are +# exactly zero, which nothing can be measured *relative* to -- those get an +# absolute tolerance instead. fw.check_close("(a) div = 3", div_a, 3.0, rtol=1e-6) -fw.check_close("(b) div = 0 (rotation)", div_b + 1.0, 1.0, rtol=1e-6) -fw.check_close("(c) div = 0 (shear)", div_c + 1.0, 1.0, rtol=1e-6) +fw.check_abs("(b) div = 0 (rotation)", div_b, atol=1e-9) +fw.check_abs("(c) div = 0 (shear)", div_c, atol=1e-9) for key, measured in (("a", div_a), ("b", div_b), ("c", div_c)): sign = int(np.sign(np.round(measured.mean(), 6))) @@ -1053,8 +1141,6 @@ for key, measured in (("a", div_a), ("b", div_b), ("c", div_c)): :class: dropdown ```python -zero = np.zeros_like(X) - Aa = (X, Y, Z) Ab = (-Y, X, zero) Ac = (X, -Y, zero) @@ -1062,18 +1148,6 @@ Ac = (X, -Y, zero) div_a = divergence(*Aa, dx, dy, dz) div_b = divergence(*Ab, dx, dy, dz) div_c = divergence(*Ac, dx, dy, dz) - -for name, d in [("(a) outward flow", div_a), ("(b) rotation", div_b), ("(c) shear", div_c)]: - print(f"{name:20s} div = {d.mean():+.3f}") - -fig, axes = plt.subplots(1, 2, figsize=(12, 4.6)) -for ax_, (name, A, d) in zip(axes, [("(a) outward flow", Aa, div_a), - ("(c) shear flow", Ac, div_c)]): - fw.show_field_slice(X, Y, Z, *A[:2], background=d, ax=ax_, density=1.1, - vmin=-3, vmax=3, colorbar=(ax_ is axes[-1]), - label=r"$\nabla\cdot\boldsymbol{A}$ [s$^{-1}$]", title=name) -plt.tight_layout() -plt.show() ``` ::: @@ -1091,7 +1165,7 @@ Put a box at the origin: fluid pours out through the left and right walls and in ### Task 13 — the divergence as a charge detector -Maxwell's first equation says +Gauss's law, for a field in vacuum, says $$ \nabla\cdot\boldsymbol{E} = \frac{\rho_v}{\varepsilon_0} $$ @@ -1101,6 +1175,8 @@ Test that pointwise on a real source. Not a point charge — that is an idealisa $$ \rho_v(r) = \rho_{v0}\,e^{-r^{2}/a^{2}}, \qquad \rho_{v0} = 10^{-9}\ \text{C/m}^3, \qquad a = 0.5\ \text{m} $$ +Here $a$ is the **width of the blob**. In Task 9 the same letter was an electrode separation — the second overloaded symbol on this page, after $\rho$. The code keeps them apart as `a` and `a_sep`; your algebra has only the context to go on. + Integrating that over a sphere of radius $r$ gives the charge it encloses (bookwork — you do not need to do the integral now): $$ Q_{\text{enc}}(r) = \int_0^{r}\!\rho_v\,4\pi r'^{2}\,dr' = 4\pi\rho_{v0}\left[\frac{a^{3}\sqrt{\pi}}{4}\operatorname{erf}\!\left(\frac{r}{a}\right) - \frac{a^{2}r}{2}e^{-r^{2}/a^{2}}\right] $$ @@ -1116,50 +1192,22 @@ from scipy.special import erf a, rho_v0 = 0.5, 1e-9 -# Task 13 -# 1. rho_v = rho_v0 * exp(-r^2 / a^2) on the grid. -# 2. E_r from the formula above, using rs in the denominators. (The two -# bracketed terms very nearly cancel for r << a, so the closed form -# loses accuracy below r ~ 1e-6 m; on this grid the only such sample -# is the origin, where the r-hat components are zero anyway.) -# 3. Turn the radial magnitude into components along r-hat: -# Ex_b = E_r * rhx, and likewise for y and z. -# 4. div_blob = divergence(...), and compare it against rho_v / epsilon_0 -# everywhere -- including inside the source. -# 5. Plot both, side by side, in the z = 0 plane. Pass the SAME vmin and -# vmax to each panel, or they get separate auto-scales and the two -# pictures are no longer comparable -- which is the whole point: -# hi = float(np.nanmax(rho_v / epsilon_0)) -# fig, axes = plt.subplots(1, 2, figsize=(12, 4.4)) -# fw.show_scalar_slice(X, Y, Z, div_blob, ax=axes[0], cmap="magma", -# vmin=0, vmax=hi, label=..., title=...) -# fw.show_scalar_slice(X, Y, Z, rho_v / epsilon_0, ax=axes[1], ...) - -# Write your code here: - - - -# --- self-check (leave this alone) --- -peak = np.nanmax(rho_v / epsilon_0) -_e = np.abs(div_blob[interior] - (rho_v / epsilon_0)[interior]) / peak -cart_worst, cart_median = float(_e.max()), float(np.median(_e)) -fw.check(f"div E = rho_v/eps0 pointwise (worst {cart_worst:.2%} of peak)", - cart_worst < 0.05, "check the component construction Ex_b = E_r * rhx") -``` - -:::{admonition} Solution — Task 13 -:class: dropdown - -```python +# --- given: the charge density, and the field Gauss's law gives it --- +# (Transcribing the erf expression teaches nothing; deciding what to do with +# it does. The two bracketed terms nearly cancel for r << a, so the closed +# form loses accuracy below r ~ 1e-6 m; on this grid the only such sample is +# the origin, where the r-hat components are zero anyway.) rho_v = rho_v0 * np.exp(-r**2 / a**2) - E_r = rho_v0 / (epsilon_0 * rs**2) * ( (a**3 * np.sqrt(np.pi) / 4) * erf(rs / a) - (a**2 * rs / 2) * np.exp(-rs**2 / a**2) ) -Ex_b, Ey_b, Ez_b = E_r * rhx, E_r * rhy, E_r * rhz -div_blob = divergence(Ex_b, Ey_b, Ez_b, dx, dy, dz) +# Task 13 -- two blanks. +# E_r is a radial MAGNITUDE. Give it a direction, then differentiate. +Ex_b, Ey_b, Ez_b = ___ # components along (rhx, rhy, rhz) +div_blob = ___ # your Task 10 operator +# --- given: the two pictures, forced onto one scale so they are comparable --- hi = float(np.nanmax(rho_v / epsilon_0)) units = r"[V m$^{-2}$]" fig, axes = plt.subplots(1, 2, figsize=(12, 4.4)) @@ -1170,8 +1218,23 @@ fw.show_scalar_slice(X, Y, Z, rho_v / epsilon_0, ax=axes[1], cmap="magma", label plt.tight_layout() plt.show() -print(f"peak of rho_v/eps0 : {np.nanmax(rho_v/epsilon_0):8.2f}") +print(f"peak of rho_v/eps0 : {np.nanmax(rho_v/epsilon_0):8.2f}") print(f"peak of measured div: {np.nanmax(div_blob):8.2f}") + +# --- self-check (leave this alone) --- +peak = np.nanmax(rho_v / epsilon_0) +_e = np.abs(div_blob[interior] - (rho_v / epsilon_0)[interior]) / peak +cart_worst, cart_median = float(_e.max()), float(np.median(_e)) +fw.check(f"div E = rho_v/eps0 pointwise (worst {cart_worst:.2%} of peak)", + cart_worst < 0.05, "check the component construction Ex_b = E_r * rhx") +``` + +:::{admonition} Solution — Task 13 +:class: dropdown + +```python +Ex_b, Ey_b, Ez_b = E_r * rhx, E_r * rhy, E_r * rhz +div_blob = divergence(Ex_b, Ey_b, Ez_b, dx, dy, dz) ``` ::: @@ -1195,6 +1258,8 @@ Everything so far used the Cartesian formula, because `np.gradient` differentiat Cylindrical $\varrho=\sqrt{x^2+y^2}$ is the distance from the $z$-axis; spherical $r=\sqrt{x^2+y^2+z^2}$, used throughout this lab, is the distance from the origin. They are written differently precisely to keep them apart. +One reading note: the spherical coordinates are *named* $(r,\phi,\theta)$, but the terms in the row above are listed $r$, then $\theta$, then $\phi$ — the order in which the scale factors $(1,\ r,\ r\sin\theta)$ are derived. A sum does not care about the order of its terms; only about which ones are in it. + Both fields you have built are spherically symmetric — $\boldsymbol{E} = E_r(r)\,\hat{\boldsymbol{r}}$, with no $\theta$ or $\phi$ dependence — so two of the three spherical terms vanish and the divergence collapses to one ordinary derivative along one line: $$ \nabla\cdot\boldsymbol{E} \;=\; \frac{1}{r^{2}}\frac{d}{dr}\!\left(r^{2}E_r\right) $$ @@ -1213,12 +1278,28 @@ div_blob_sph = np.gradient(r_line**2 * E_R_blob, dr) / r_line**2 div_point_sph = np.gradient(r_line**2 * E_r_point, dr) / r_line**2 rho_v_line = rho_v0 * np.exp(-r_line**2 / a**2) + +# --- given: the radial profile Task 13 asserted but never drew --- +Q_total = np.pi**1.5 * rho_v0 * a**3 # all of the blob's charge +plt.figure(figsize=(5.8, 4.2)) +plt.plot(r_line, E_R_blob, "k", lw=1.8, label="$E_r(r)$, exact") +plt.plot(r_line, rho_v0 * r_line / (3 * epsilon_0), "C1--", lw=1.2, + label=r"small $r$: $\rho_{v0}r/3\varepsilon_0$") +plt.plot(r_line, Q_total / (4 * np.pi * epsilon_0 * r_line**2), "C2:", lw=1.4, + label=r"large $r$: $Q/4\pi\varepsilon_0 r^2$") +plt.axvline(a, color="C0", lw=1, alpha=0.6) +plt.annotate("$r = a$", (a, 1.12 * E_R_blob.max()), color="C0", ha="left") +plt.xlabel("$r$ [m]"); plt.ylabel(r"$E_r$ [V m$^{-1}$]") +plt.ylim(0, 1.25 * E_R_blob.max()); plt.grid(alpha=0.3); plt.legend(fontsize=8) +plt.title("The blob's field: linear inside, inverse-square outside") +plt.show() + err_sph = np.abs(div_blob_sph - rho_v_line / epsilon_0)[1:-1] / np.max(rho_v_line / epsilon_0) print(f"blob : {r_line.size} samples on a line vs {X.size:,} in the cube") print(f" worst error {err_sph.max():.3%} of peak, median {np.median(err_sph):.4%}") print(f" Cartesian, from Task 13: {cart_worst:.3%} and {cart_median:.4%}") print(f"point: r^2 E_r varies by {np.ptp(r_line**2 * E_r_point):.1e} over the whole line") -print(f" max |div E| = {np.abs(div_point_sph).max():.1e}") +print(f" max |div E| = {np.abs(div_point_sph).max():.1e} (round-off, not physics)") ``` :::{admonition} Why anyone bothers with curvilinear coordinates @@ -1226,7 +1307,7 @@ print(f" max |div E| = {np.abs(div_point_sph).max():.1e}") Same field, same operator, same answer — from a few hundred samples on a line instead of a quarter of a million in a cube, and several times more accurately. -For the point charge the gain is not accuracy but certainty. $r^{2}E_r = q/4\pi\varepsilon_0$ is a **constant**, so its derivative is exactly zero for every $r>0$ — not "1.35% of something", but zero. Cartesian coordinates could only ever report that the divergence was small. +For the point charge the gain is not accuracy but certainty. $r^{2}E_r = Q/4\pi\varepsilon_0$ is a **constant**, so its derivative is *analytically* zero for every $r>0$ — not "1% of something", but zero, by one line of algebra. What the cell prints is only how well double precision can subtract two equal numbers: $10^{-13}$ or so, and exactly $0$ if the arithmetic happens to cancel. Change `dr` and that last digit will move; the algebra will not. Cartesian coordinates could never have got past "the divergence is small". Match your coordinates to the symmetry of the source and three noisy numerical derivatives collapse into one line of algebra. That is what the second and third rows of the table are for. ::: @@ -1237,7 +1318,9 @@ Match your coordinates to the symmetry of the source and three noisy numerical d Part 5 used the *differential* form of Gauss's law, which compares two numbers at one point. The *integral* form connects a volume to the surface enclosing it: -$$ \oint_S \boldsymbol{E}\cdot d\boldsymbol{s} \;=\; \int_v \nabla\cdot\boldsymbol{E}\;dv \;=\; \frac{Q_{\text{enc}}}{\varepsilon_0} $$ +$$ \oint_S \boldsymbol{E}\cdot\hat{\boldsymbol{n}}\,dS \;=\; \int_{\mathcal{D}} \nabla\cdot\boldsymbol{E}\;dV \;=\; \frac{Q_{\text{enc}}}{\varepsilon_0} $$ + +with $S$ the closed surface, $\hat{\boldsymbol{n}}$ its outward unit normal, and $\mathcal{D}$ the volume it encloses. The first equality is the **divergence theorem** — pure vector calculus, true for any well-behaved field. The second is the physics. Together: measuring $\boldsymbol{E}$ on a closed surface tells you how much charge is inside, and nothing about how it is arranged, or about any charge outside. @@ -1272,22 +1355,24 @@ def closed_box_flux(Ax, Ay, Az, half_width): return flux_x + flux_y + flux_z -# Task 9 (using the blob field Ex_b, Ey_b, Ez_b from Task 13) -# 1. Finish closed_box_flux above. -# 2. For h = 0.6, 1.0 and 1.4 m, print three numbers in V*m and check they -# agree: the surface integral; the volume integral of div_blob over the -# same cube (fw.volume_integral(div_blob[s, s, s], dx, dy, dz), with -# i0, i1 = fw.box_indices(X, h)); and the enclosed charge, the volume -# integral of rho_v over that cube divided by epsilon_0. -# 3. Keep the h = 1.0 m surface integral as `flux_1m` -- the self-check -# below needs that exact name. -# 4. Now settle Task 12 by measurement rather than by argument: print -# closed_box_flux for fields (b) and (c). Both look like they are -# throwing fluid outwards somewhere; a closed surface is the arbiter. - -# Write your code here: +# --- given: three routes to the same number, and the Task 12 arbiter --- +# Finish closed_box_flux above; everything below is written for you. +flux_1m = closed_box_flux(Ex_b, Ey_b, Ez_b, 1.0) +print(f"{'h [m]':>6} {'surface':>12} {'volume':>12} {'Q_enc/eps0':>12}") +for h in (0.6, 1.0, 1.4): + i0, i1 = fw.box_indices(X, h) + s_ = slice(i0, i1 + 1) + surf = closed_box_flux(Ex_b, Ey_b, Ez_b, h) + vol = fw.volume_integral(div_blob[s_, s_, s_], dx, dy, dz) + qenc = fw.volume_integral(rho_v[s_, s_, s_], dx, dy, dz) / epsilon_0 + print(f"{h:6.1f} {surf:12.3f} {vol:12.3f} {qenc:12.3f}") +# Task 12 settled by measurement rather than by argument. Both (b) and (c) +# look like they throw fluid outwards somewhere; a closed surface is the +# arbiter, and it never had to differentiate anything. +print(f"\nflux of (b), the rotation : {closed_box_flux(-Y, X, zero, 1.0):+.2e}") +print(f"flux of (c), the shear : {closed_box_flux(X, -Y, zero, 1.0):+.2e}") # --- self-check (leave this alone) --- i0, i1 = fw.box_indices(X, 1.0) @@ -1309,22 +1394,6 @@ fw.check_scalar("divergence theorem: surface = volume", flux_1m, flux_z = (fw.area_integral(Az[s, s, i1], dx, dy) - fw.area_integral(Az[s, s, i0], dx, dy)) return flux_x + flux_y + flux_z - - -flux_1m = closed_box_flux(Ex_b, Ey_b, Ez_b, 1.0) # step 6 - -print(f"{'h [m]':>6} {'surface':>12} {'volume':>12} {'Q_enc/eps0':>12}") -for h in (0.6, 1.0, 1.4): - i0, i1 = fw.box_indices(X, h) - s = slice(i0, i1 + 1) - surf = closed_box_flux(Ex_b, Ey_b, Ez_b, h) - vol = fw.volume_integral(div_blob[s, s, s], dx, dy, dz) - qenc = fw.volume_integral(rho_v[s, s, s], dx, dy, dz) / epsilon_0 - print(f"{h:6.1f} {surf:12.3f} {vol:12.3f} {qenc:12.3f}") - -zero = np.zeros_like(X) -print(f"\nflux of (b), the rotation : {closed_box_flux(-Y, X, zero, 1.0):+.2e}") -print(f"flux of (c), the shear : {closed_box_flux(X, -Y, zero, 1.0):+.2e}") ``` ::: @@ -1340,7 +1409,7 @@ The number grows with $h$ and then stops: once the cube holds essentially all th Run the same surface integral on the point-charge field from Task 7 — the one whose divergence you could never measure at the origin, because you had to mask it away. -Rearranged, Gauss's law turns your flux into a **charge meter**: $Q_{\text{enc}} = \varepsilon_0 \oint_S \boldsymbol{E}\cdot d\boldsymbol{s}$. So weigh the charge inside each box, in coulombs, and compare it with the 1 nC you put there. +Rearranged, Gauss's law turns your flux into a **charge meter**: $Q_{\text{enc}} = \varepsilon_0 \oint_S \boldsymbol{E}\cdot\hat{\boldsymbol{n}}\,dS$. So weigh the charge inside each box, in coulombs, and compare it with the 1 nC you put there. ```{code-cell} ipython3 print("box half-width charge it finds") @@ -1367,7 +1436,7 @@ So the whole source sits at one point, where $\nabla\cdot\boldsymbol{E}$ is not The same statement for magnetism carries no source term at all: -$$ \nabla\cdot\boldsymbol{B} = 0 \qquad\Longleftrightarrow\qquad \oint_S \boldsymbol{B}\cdot d\boldsymbol{s} = 0 \ \ \text{for every closed } S $$ +$$ \nabla\cdot\boldsymbol{B} = 0 \qquad\Longleftrightarrow\qquad \oint_S \boldsymbol{B}\cdot\hat{\boldsymbol{n}}\,dS = 0 \ \ \text{for every closed } S $$ Run this measurement around any closed surface anywhere and you get zero: there are no magnetic monopoles, and field lines of $\boldsymbol{B}$ never begin and never end. ::: @@ -1376,23 +1445,44 @@ Run this measurement around any closed surface anywhere and you get zero: there Task 11 measured $\nabla\cdot\boldsymbol{B} = 0$ for the Earth's dipole and got 1.8% — grid error, not physics. Now make the same claim without differentiating anything: put a closed surface around the dipole and weigh what comes out. +One warning before you read the numbers. A box centred on the origin is a +suspiciously easy test for *this* dipole: with $\boldsymbol{m} = \hat{\boldsymbol{z}}$, $B_x$ and $B_y$ are odd in $z$ and $B_z$ is even, so on a $z$-symmetric box the faces cancel in pairs *before* any physics enters. A lopsided box is the honest one, so the cell below runs both. + ```{code-cell} ipython3 r_dot_m = Z Bx = 3*X*r_dot_m / r_safe**5 By = 3*Y*r_dot_m / r_safe**5 Bz = (3*Z*r_dot_m - r_safe**2) / r_safe**5 -print(" h [m] flux of B flux of the radial flow v") -for h in (0.6, 1.0, 1.4): - f_B = closed_box_flux(*(np.nan_to_num(q) for q in (Bx, By, Bz)), h) - f_v = closed_box_flux(*(np.nan_to_num(q / r_safe**3) for q in (X, Y, Z)), h) - print(f" {h:4.1f} {f_B:+12.2e} {f_v:+12.4f}") -print(f"\n 4*pi = {4*np.pi:.4f}") +B = tuple(np.nan_to_num(q) for q in (Bx, By, Bz)) +v = tuple(np.nan_to_num(q / r_safe**3) for q in (X, Y, Z)) + +# --- given: the same surface integral over any grid-aligned box, centred +# on the origin or not. Same six faces, same three pairs as Task 14. +def box_flux(A, x0, x1, y0, y1, z0, z1): + i = [int(np.argmin(np.abs(axis - q))) for q in (x0, x1, y0, y1, z0, z1)] + sx, sy, sz = slice(i[0], i[1]+1), slice(i[2], i[3]+1), slice(i[4], i[5]+1) + return (fw.area_integral(A[0][i[1], sy, sz], dy, dz) - fw.area_integral(A[0][i[0], sy, sz], dy, dz) + + fw.area_integral(A[1][sx, i[3], sz], dx, dz) - fw.area_integral(A[1][sx, i[2], sz], dx, dz) + + fw.area_integral(A[2][sx, sy, i[5]], dx, dy) - fw.area_integral(A[2][sx, sy, i[4]], dx, dy)) + +boxes = [("centred, h = 0.6", (-0.6, 0.6, -0.6, 0.6, -0.6, 0.6)), + ("centred, h = 1.0", (-1.0, 1.0, -1.0, 1.0, -1.0, 1.0)), + ("centred, h = 1.4", (-1.4, 1.4, -1.4, 1.4, -1.4, 1.4)), + ("lopsided in z ", (-1.0, 1.0, -1.0, 1.0, -0.6, 1.0)), + ("lopsided in x, z", (-0.6, 1.0, -1.0, 1.0, -0.6, 1.0))] + +print(" box flux of B flux of the radial flow v") +for name, lim in boxes: + print(f" {name} {box_flux(B, *lim):+11.2e} {box_flux(v, *lim):+12.4f}") +print(f"\n 4*pi = {4*np.pi:.4f}; the integrator misses it by " + f"{4*np.pi - box_flux(v, -1, 1, -1, 1, -1, 1):.1e} on the flow") # --- self-check (leave this alone) --- -fw.check("the dipole encloses nothing, at any radius", - max(abs(closed_box_flux(*(np.nan_to_num(q) for q in (Bx, By, Bz)), h)) - for h in (0.6, 1.0, 1.4)) < 1e-9) +fw.check("the dipole encloses nothing -- even in a box that is not centred on it", + max(abs(box_flux(B, *lim)) for _, lim in boxes) < 1e-2) +fw.check("...and the same integrator does find the tap in the radial flow", + abs(box_flux(v, -1, 1, -1, 1, -1, 1) - 4*np.pi) < 0.01 * 4*np.pi) ``` :::{admonition} Two kinds of "divergence-free" @@ -1400,7 +1490,9 @@ fw.check("the dipole encloses nothing, at any radius", The radial flow returns $4\pi$ through every surface, whatever its size — there is a tap at the origin, and every box finds the same one, exactly as every box found the same 1 nC a moment ago. -The dipole returns **zero to machine precision**, at every radius. Not 1.8%, not small: zero. Shrink the surface as tightly as you like around the source and it stays zero, because there is no source to find. That is $\nabla\cdot\boldsymbol{B} = 0$ stated in the form that admits no exception, and it is why the integral form was worth building: it settles at the source what the differential form could only report away from it. +The dipole returns **nothing**, through any of them. On the three centred boxes the answer is zero to machine precision — but read that with the warning above in mind: those boxes cancel the field against itself by symmetry, so they were never going to say anything else. The lopsided boxes are the measurement that counts, and they return $-2.5\times10^{-3}$ and $-2.2\times10^{-4}$. That sounds like a retreat until you put it beside the column next to it: the very same integrator, on the very same grid, misses $4\pi$ by $6.8\times10^{-3}$ on the radial flow. **The dipole's flux is zero to better than the accuracy with which this method can measure anything at all.** + +So the two "divergence-free" fields are not the same statement. The flow has a tap you can find by shrinking a surface onto it; the dipole has nothing to find, at any size or placement of the surface. That is $\nabla\cdot\boldsymbol{B} = 0$ in the form that admits no exception, and it is why the integral form was worth building: it settles matters *at* the source, where the differential form had to be masked away. ::: ### Where do the 1% errors come from? @@ -1475,12 +1567,13 @@ Divergence cannot see circulation. The operator that can is the **curl**, the th The exercises in your lecture notes are the written homework. Below is the lab's own extension — the one piece that is computational rather than pen-and-paper, and that carries the afternoon's operators into a system you can feel. -**A heat source in a room.** Replace the spherical blob with a flat rectangular heater, $1.0 \times 0.6$ m in the $z = 0$ plane. A steady point source of power $P$ in a medium of conductivity $k$ raises the temperature as $P/4\pi k r$ — the same $1/r$ you have worked with all afternoon — so superpose a $20 \times 12$ grid of them over the rectangle, exactly as you superposed two charges in Task 8: +**A heat source in a room.** Replace the spherical blob with a flat rectangular heater, $1.0 \times 0.6$ m in the $z = 0$ plane. A steady point source of power $P$ in a medium of conductivity $k$ raises the temperature above ambient by $P/4\pi k r$ — the same $1/r$ you have worked with all afternoon. Split the plate into $N = 20 \times 12$ sub-sources, give each an equal share $P/N$ of the power, and superpose, exactly as you superposed two charges in Task 8: -$$ T(\boldsymbol{r}) = \frac{P}{4\pi k}\sum_i \frac{\Delta A}{\lvert \boldsymbol{r} - \boldsymbol{r}_i \rvert}, \qquad P = 100\ \text{W}, \qquad k_{\text{air}} = 0.026\ \text{W m}^{-1}\text{K}^{-1}, $$ +$$ T(\boldsymbol{r}) = \frac{P}{4\pi k N}\sum_{i=1}^{N} \frac{1}{\lvert \boldsymbol{r} - \boldsymbol{r}_i \rvert}, \qquad P = 100\ \text{W}, \qquad k_{\text{air}} = 0.026\ \text{W m}^{-1}\text{K}^{-1}. $$ -with $\Delta A$ the area each sample represents. Then: +Check the dimensions before you code it: $[P]/[k] = \text{W}/(\text{W m}^{-1}\text{K}^{-1}) = \text{m}\cdot\text{K}$, divided by a distance, so $T$ comes out in kelvin. A formula for a temperature that does not is a formula with a bug in it. Then: - Plot the isosurfaces. Close to the plate they should be rounded rectangles; far away they should become spheres. Why does the shape forget its source? - Compute the heat flux $\boldsymbol{q}_T = -k\nabla T$ — the same minus sign, the same reason as $\boldsymbol{E} = -\nabla V$. - Check that $\nabla\cdot\boldsymbol{q}_T \approx 0$ away from the heater, and that the closed-surface flux through a box containing the plate is *not* zero. Say what each result means physically for a room at steady state, and which of the two fields you met in Task 11 the heater resembles. +- **Then look at the number.** One metre from a 100 W panel this model predicts about $+290$ K above ambient — a room at 300 °C. The arithmetic is right, so the *physics* is wrong. Which assumption failed? (Two are worth naming: what actually carries heat through air, and where this solution puts the room's walls.) Re-run it with $k = 1.5$ W m⁻¹K⁻¹, the conductivity of soil, and you get $+5$ K — the same equations, now describing a buried heating element, which is a problem pure conduction really does solve. From d56995f849d8d1ccb1263964e3f0c66f80cacd1f Mon Sep 17 00:00:00 2001 From: ARS183 <1028762817@qq.com> Date: Tue, 1 Sep 2026 15:26:51 +0200 Subject: [PATCH 06/17] Add the Chapter 1 and 2 lecture notes as TeachBook pages --- book/1_gradient_divergence_curl/coord_sys.md | 315 ++++++++++++++++++ book/1_gradient_divergence_curl/curl.md | 106 ++++++ book/1_gradient_divergence_curl/divergence.md | 250 ++++++++++++++ .../figures/Cartframe.png | Bin 0 -> 33103 bytes .../figures/circulation.png | Bin 0 -> 20437 bytes .../figures/crossprod.png | Bin 0 -> 21989 bytes .../figures/cylsphere.png | Bin 0 -> 96170 bytes .../figures/dcpoth.png | Bin 0 -> 314878 bytes .../figures/dcpotv.png | Bin 0 -> 219574 bytes .../figures/rotCartframe.png | Bin 0 -> 92088 bytes book/1_gradient_divergence_curl/gradient.md | 159 +++++++++ book/1_gradient_divergence_curl/intro.md | 96 +++++- .../sums_series_approx.md | 108 ++++++ book/_toc.yml | 8 +- 14 files changed, 1038 insertions(+), 4 deletions(-) create mode 100644 book/1_gradient_divergence_curl/coord_sys.md create mode 100644 book/1_gradient_divergence_curl/curl.md create mode 100644 book/1_gradient_divergence_curl/divergence.md create mode 100644 book/1_gradient_divergence_curl/figures/Cartframe.png create mode 100644 book/1_gradient_divergence_curl/figures/circulation.png create mode 100644 book/1_gradient_divergence_curl/figures/crossprod.png create mode 100644 book/1_gradient_divergence_curl/figures/cylsphere.png create mode 100644 book/1_gradient_divergence_curl/figures/dcpoth.png create mode 100644 book/1_gradient_divergence_curl/figures/dcpotv.png create mode 100644 book/1_gradient_divergence_curl/figures/rotCartframe.png create mode 100644 book/1_gradient_divergence_curl/gradient.md create mode 100644 book/1_gradient_divergence_curl/sums_series_approx.md diff --git a/book/1_gradient_divergence_curl/coord_sys.md b/book/1_gradient_divergence_curl/coord_sys.md new file mode 100644 index 0000000..4d3ccca --- /dev/null +++ b/book/1_gradient_divergence_curl/coord_sys.md @@ -0,0 +1,315 @@ +# Coordinate systems + +Three-dimensional space can be built from many frames of reference, but here it is built from the rectangular, cylindrical and spherical coordinate systems. + +- The **rectangular** (Cartesian) coordinate system is characterised by the three base vectors $\hat{\boldsymbol x},\hat{\boldsymbol y},\hat{\boldsymbol z}$ with coordinates and ranges $-\infty0$. The total current that is injected into the ground times the total resistance equals the electric potential, which is Ohm's law. The total resistance is given by the electric resistivity $\rho$ divided by $4\pi$ times the radial distance from the current injection point. + +Now suppose there is a surface at $z=0$ between non-conductive air and the conductive subsurface, and the injection point is at the surface $z=0$. In that case the current can only go into the ground below the surface, hence for $z>0$, and the relevant surface area is $2\pi r^2$, because the current is now distributed over the surface area of half a sphere. Therefore, anywhere in the half-space $z>0$ the electric potential is given by + +$$ +V(x,y,z) = \frac{\rho I}{2\pi r}, +$$ (eq:dcVhf) + +where again $r>0$. + +You see that the electric potential depends on the value of the electric resistivity even though it does not occur in {eq}`eq:pot`. This is because the electric potential depends on the current strength, and that in turn depends on the resistivity of the ground through which this current must flow. When it is a constant it is merely a scaling parameter, but when it is a function of position it can become a complicated relation that must be found numerically. + +### Two electrodes at the surface + +{numref}`fig-dcpoth` and {numref}`fig-dcpotv` show a plot of the electric potential $V(x,y,z)$, for $z=0$ and for $y=0,\ z>0$ respectively. The arrows in the plots indicate the vector directions of the electric current. For this configuration we have the electric potential given by + +$$ +\begin{aligned} +V(x,y,z) &= V(x-a/2,y,z) - V(x+a/2,y,z), \\ +V(x,y,z) &= \frac{\rho I}{2\pi}\left(\frac{1}{\sqrt{(x-a/2)^2+y^2+z^2}} - \frac{1}{\sqrt{(x+a/2)^2+y^2+z^2}}\right), +\end{aligned} +$$ (eq:Vpdp) + +where the point $x=a/2$ is the point of current injection (current goes into the ground, also known as source) and the point $x=-a/2$ is the current extraction point (current goes out of the ground, also known as sink), for which reason the potential related to that location is negative. + +```{figure} figures/dcpoth.png +:name: fig-dcpoth +:width: 75% + +Electric potential difference and electric current density vectors on the ground surface $z=0$, with two electrodes at $x=-a/2$ and $x=a/2$. Distances are normalised to the electrode spacing $a$. +``` + +```{figure} figures/dcpotv.png +:name: fig-dcpotv +:width: 85% + +Electric potential difference and electric current density vectors in the vertical cross-section $y=0,\ z>0$, with two electrodes at $x=-a/2$ and $x=a/2$. Distances are normalised to the electrode spacing $a$. +``` + +To make the current run in the subsurface, the two points must be connected to a current source above the ground through an electronically controlled connection with a battery or other charge-storage/current-producing device. This is because electric current can only run in closed loops. The total current running in the wire above the ground is distributed in the ground, and fractions of current run everywhere in the subsurface where the resistivity is finite. + +## The magnetic dipole + +Another example is the magnetic field of the Earth, which to first order is a dipole field. The source is therefore different from what we have seen in the fluid flow and electric potential problems. The Earth's magnetic field (to first order) is the field generated by a magnetic north pole and a magnetic south pole very close together. The dipole vector $\boldsymbol m$ points from the south pole of the dipole to the north pole, and its size is given by the strength of the dipole. The magnetic field $\boldsymbol B$ is given by + +$$ +\boldsymbol B = \frac{3\boldsymbol r(\boldsymbol r\cdot\boldsymbol m) - r^2\boldsymbol m}{r^5}. +$$ (eq:magB) + +For this particular solution $\nabla\cdot\boldsymbol B = 0$ for all points in space, also at the source at $\boldsymbol r=\boldsymbol 0$. + +## Exercises + +1. If $(\boldsymbol v\cdot\hat{\boldsymbol n})\hat{\boldsymbol n}$ in {eq}`eq:vflux` is the fraction of $\boldsymbol v$ that leaves the volume $\mathbb{D}$ through the surface $\mathbb{S}$, what is the fraction of the flow that does not leave the volume $\mathbb{D}$? +2. Carry out the differentiations to show that the expression for $f(r)$ in {eq}`eq:NF` is correct. +3. The total current that can be injected into the ground must run in a cable from the source (battery and signal conditioner) to the ground. Once it is in the ground it is free to go anywhere, but the total volume integral must remain equal to the current that runs in the cable, because of the continuity of electric current. We have used the symbol $I$ to denote the total current, and in {eq}`eq:Icur` you have seen a sequence of expressions that resulted in finding the unknown coefficient $A$. + + Another way of finding this result is by observing that the electric potential is the solution of {eq}`eq:laplV` under the condition that a current is injected at the origin. Hence the actual problem is obtained if you take the divergence of both sides of {eq}`eq:Ohm`. This results in $\nabla\cdot\boldsymbol E = \rho\,\nabla\cdot\boldsymbol J$. Integrate both sides of this equation over a spherical volume with fixed radius $r$ and use Gauss' theorem to show that + + $$ + -\int_{\mathbb{S}}\hat{\boldsymbol n}\cdot(\nabla V)\,\mathrm{d}S = \rho\int_{\mathbb{S}}\hat{\boldsymbol n}\cdot\boldsymbol J\,\mathrm{d}S . + $$ (eq:fluxintE) + + The right-hand side is a constant, because it is equal to the total current $I$ that comes from the source and runs in the cable, and therefore it must run out across any spherical surface around the current injection point. Hence, we find + + $$ + \int_{\mathbb{S}}\hat{\boldsymbol n}\cdot(\nabla V)\,\mathrm{d}S = -\rho I . + $$ + + Substitute the solution proposed for $V$ of {eq}`eq:pot` with $B=0$ in this equation to verify that $A=\rho I/(4\pi)$. +4. Evaluate the gradient of the potential expressed in {eq}`eq:Vpdp` and give the expression for the electric current density in the ground at and below the ground surface. Write a Python script that computes the electric potential and the electric current density on the ground surface and in a vertical cross-section, and reproduce the plots of {numref}`fig-dcpoth` and {numref}`fig-dcpotv`. Normalise distance to the electrode spacing $a$ and avoid the points $x=\pm a/2$. You can choose any colour map you like for the potential and choose a contrasting colour for the arrows representing the current lines and directions. +5. The electric field associated with the electric potential given in {eq}`eq:Vpdp` can be evaluated by taking the gradient of the potential, because of {eq}`eq:EgradV`. Give an argument why the flux integral of the electric field $\int_{\mathbb{S}}\hat{\boldsymbol n}\cdot\boldsymbol E\,\mathrm{d}S = 0$ for every closed and piecewise smooth surface that does not include the current injection and extraction points $x=\pm a/2$. +6. Verify that the magnetic field expressed in {eq}`eq:magB` is divergence free for all points in space. +7. Show that the divergence of a vector field in cylindrical and in spherical coordinates is given by + + $$ + \begin{aligned} + \nabla\cdot\boldsymbol v(\varrho,\phi,z) &= \frac{1}{\varrho}\left[\partial_\varrho(\varrho v_\varrho) + \partial_\phi v_\phi\right] + \partial_z v_z, \\ + \nabla\cdot\boldsymbol v(r,\phi,\theta) &= \frac{1}{r^2}\partial_r(r^2 v_r) + \frac{1}{r\sin(\theta)}\left[\partial_\theta(\sin(\theta)v_\theta) + \partial_\phi v_\phi\right]. + \end{aligned} + $$ + + Please remember that in cylindrical coordinates $\varrho=\sqrt{x^2+y^2}$ and in spherical coordinates $r=\sqrt{x^2+y^2+z^2}$! +8. Consider a general flow field $\boldsymbol v(\boldsymbol r) = \left(v_x(y,z),\,v_y(x,z),\,v_z(x,y)\right)$ flowing in an open space containing a closed surface $\mathbb{S}$. Evaluate the flux integral $\int_{\mathbb{S}}\hat{\boldsymbol n}\cdot\boldsymbol v\,\mathrm{d}S$. +9. Show that when $\boldsymbol v(\boldsymbol r) = \boldsymbol a\,p(\boldsymbol r)$, where $\boldsymbol a$ is an arbitrary constant vector and $p(\boldsymbol r)$ is a continuously differentiable scalar function, Gauss' integral theorem gives + + $$ + \int_{\mathbb{S}}p\,\hat{\boldsymbol n}\,\mathrm{d}S = \int_{\mathbb{D}}\nabla p\,\mathrm{d}V, + $$ + + which is Gauss' theorem for the gradient. +10. Show that when $\boldsymbol v(\boldsymbol r) = \boldsymbol a\times\boldsymbol w(\boldsymbol r)$, where $\boldsymbol a$ is an arbitrary constant vector and $\boldsymbol w(\boldsymbol r)$ is a continuously differentiable vector function, Gauss' integral theorem gives + + $$ + \int_{\mathbb{S}}\hat{\boldsymbol n}\times\boldsymbol w\,\mathrm{d}S = \int_{\mathbb{D}}\nabla\times\boldsymbol w\,\mathrm{d}V, + $$ + + which is Gauss' theorem for the curl. diff --git a/book/1_gradient_divergence_curl/figures/Cartframe.png b/book/1_gradient_divergence_curl/figures/Cartframe.png new file mode 100644 index 0000000000000000000000000000000000000000..b5fdc455b9d0d11e84517122ca74d7825a482fcd GIT binary patch literal 33103 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

-#|klICk%b#w>eKw&)AX0ii|0O+qi-GOf5w6>;FE$sz z{IBM6sj0jJ>P^GuZiM4sFjf5>@3x3 zKnv53G8V!zpV2v3g^sqbAJFjyFp*iJKbq;?U1RdW*VngZe|vakv|=eS>1KV$#{Hwo z?=PkASfHV~LuD1TT&RY^g$QTfY}n;!_4?+HLhjwWcU4GAa(x0!BzHJ8NN(rjtG2*C z-3?eUaY>_@O>%j>nV7XokPM0sLn_+O3Jk=>jAqJbm5kZyxbMh987gL1Ew@=HdlIx# zxzW~Zx};R3-|NEYqrxCL_Q?|R=44*7=#B8e!q|Q~1mZ&^i5tTu(_N~as2zp+y8%9i zAbVdUt9dv&H{-Q6skxEY;7tF(DqD%_a-#7Skwmd&;t#pUKisY?R4$IrojrRN#;!YZ zRCaqFuUPx`5; zLO0~e4)Dn+A7Evlr_glAp7#D+) zYTPZN`sQm0ga97u+J^!Xmoxp?1=e`pwIk2DCfV<%o0`oRIk`>HP~;txGXi!V@1HJ@ zde~VdV$GOGJ#y7JW~HjcXEZLo=0X6W&uKc*>+=hGbJ^lBEAuEPH^F3eqn#H!a@Q4# zKMG6~i{V3aY;pcRbP^SSLG3KC%nkc2+a583^NB&)zyD9loUH`cRrF8yw}Y3 z9;GEo#___O!}#c$@vB&Y#PgSmkdN}xSDg+LJjZ^_-0;J%=R15>Q*F?fV~~z7*bEdL z=B4Z864xz(PYI1}6H$hu^O#?eHbi}87v^kW5J(+v;%t={xsf?nQr+(Z!n9$Jw=YX^ z)p)cb=(}`?we?JT*@`(p(>9ZL=Dq|`CB}N7(N0yeyefFE)T14rrW4H@tNs$fPoYS0 zjFpno0oN?D&*Nr=TBzAnGO=oV0qY6p>Ej(OS*uagMbU{=-0GauE_c{n_hoGP6wOxy zrPhxPuC$P&n*kuu@y^^rGkJ}`8CGh7wD#Q3A(_GPF^|KypFaWv^=+T#@5@$b3cXe0 z=`pyzKzvPJlY@{;-f=B7DuT~stOOIcKHH~iXUzWQZpy#Z6kw0qz`*?cc`Gg}w+YWA zD3=(oJ`xU9lfZe6rKi<-AtPaB1E_r}=R(_wNth5`ZBGHRm_H*pSE5unC@M%0x~4Om zixx1z&t^1~tyGb!v0CD4mzEea&)VZyO>N$;Y*KwA-Ogz;`H9Na#`W)y^(gy*u2#;K zhh7R}R1LG5AAMlnrGMxB%|IVSC%ZCJ8`wi_n$i>rz^*jBxA>y8-0}neHwnJ*!+&an;teH-2j3Z2`QMnq#No4eL=$MYyR) zw95)?8t`Sl$h&U0*r+`F(S~Ice->WKH;)>lx&2DJC3678e;Lsp#-c&*qt#XAAgTnS zR^`=7ilD<`E@LJTJLb)f4~uWwSFH~@N3`9-a;@<4Lb`Xtm?_X)@n6j0PN5QIb&DaJ zI$Yt)tyoEPMW;v{67GTRr?@4gUK=>ru7S|CLDw85lJPn&Tp5O1k2NNny`Smnf| zkutshocoSZt~;$ruX`3XZ^Faju=!njt}PZhR<*xx&>z?)hT@bw%wUG)?&2wg?f~7O z+X@~`ybXn=3RCC|d*|YG6Z6=~EobB`kXkg(G>6q3AMFQGOR$*qRoVxvs2US{<9H7m zZll#J;8$g7K)m`$LUjhgFDPSjuFPs_BxT2qr|d<#T5-&LZ?$DQ50thQ_>aqO6Yh3A zo|_5$&1k}KF9|7%--atw8dt*1VQl)BL#jUzu5Wwv>#R-?7jPtSC+hTHR*786`^48~ zKtBI3d5QW{5OF`OZ0u>aRh9wBtK0tF-oUMnb8ilnRDYs(fwcr;x2UKuW!B6IQr9nQ5h%VBI?sFkc7JYCH^KL$>aMoVSoT4sPqNmuRk1;{E3VJ zSIU1p2C@RUmE&KgsAC58%!LAy98eASk^nSoB2s z!m9yBrZl;3@$#M!L8wn>8H`keLs6s_Y7x(*UVj9} zEb-VKurJVrs4Gcc@Ba^p1oZ%K-lSB}L(sDT6#t7|MekIFVLZ60=+r=_m_FWwEkAQqjm zk$(#oXsg~w3!Q&(?G0Yc6CdE<;-WSgq=WQE6>>lD9qJkcct)9(8C>=J&l$if&31mm zpyan=2GOV!@d5qdKfV^C!y*F$3fy8Mrj;OL6u&Mn5z~aCtWT9!K~|q3B%X4`NLK^< z15?^E{|_-6Zf1o+y|iT21e)iA^Km9mpk_#vhmNRRsLUGZ4qMZ zqzI*!Tds8Fm=iKwcOjw-Yu@tq{znctdE@`o@lc+aoS;? zek*mTqhNx)!OqdO$ob%bZ{0)CsZkGjDJ%(6>c42?KSuwZ`85_MDStaI>X82>dvd@1#kvqFMQlfzuEcC;|76j&t_+EC|Xt zPtclu9b8R)aKiYat!R8fC|Ti7vFsnN9lgT!n_R+5JwkuPN|*YZ9XHm_$1{LTNjkqk zTMS6?1(5FX@6T;Qz|)jl&beZ|e(+x%%z_NqJuQArm-5<^sV$T)38MK+_%|$2%W3>y znitw1PNEFti9hFZK{_ktd{Vc3CU??%bP7I6X}>qFEseh61-nC!G7u74-n$m@^kxghS?}(CzL_$A*x>S#m^BEH#0t{hd^R4v$ttczkaJ2)R7ZeTK5MmZm|@R za-W<@%J5(L4do9f{puOav-f_xg9s?H&^30sOM_DPcdCO#3R7yo_xoobX2|JsHU^2` zqcH#rSz26-fsA^ASoHYE&tAP+PNhP)coK9}fXD8CiB(}jYzdttx^mIqX`M(8j&)Cn zDyVK@>O{W?AZuuFImwC-lG0Mre2rw^>-D{h_$TGhtivESithhtv33RRNvLrDXZOFg zA(RdNB=^6yAhb^?k=|HHm3oVWoPMI(hWacVnCoovRbRJx+jtz zIuU|O+~wZ6KqrsR?5NefPKE)BsE4yzw`R_#=w-bobluaT)=%vjKe zaV9IzF;tN)H=aG+kq(N}e}@jxhXs|r`u9Pf#NElK*0=#M;`hz!p@TzHF%m)pau7n~ zf)pK)V7|!LepDwiF!~IeDJV|#-f7c>JFkYepOs>J5u#@D5-Z$X2e2z%JsJM)f`u{${1W+crT{TPAjF2wVplg5*27tkfWwd z-yrViN6%#~eX_@|8HL$~#*N$@YVywqC;ptq*M+)BqT^JC<}muClcRQdEpt`7R@kdX zqYyH+ojv+Eu&CwbW0Z@(o2E6$N-IF8f;uCtH0~@*b3r%ak_we5VjM{7U}^pbtqjpx zd6~gl4W3Fw!Wif;7HBtz?cWq8q<{9f7G-9WXZ>qhstp0AUl1>z(fF))-C=C@l)m-I zRQi4H5{x8(#a%w$i)zg=GBR7<*o(DUHf6I!=PUAPIr-7CN{A9RlxjwLqDL|~%Am?! zKkt*sVl+(0Zndzq2|DvtKSQM;^IT z4dwo10C+#^DruC!nUm$D&o8V%H-(A_cUiZB&T*#lAN%84vV8PgO zE6VlvLNYTgx3?#_me+f(Dmt48Rf>b&1mEzP6^Bg zeGbQ&mo+y_o1HfMf*^mVmYuO?viQki@IJW1i>FY2`3GoyK4~P?jx#C2(B8jZ*+#EC zUD`dBL30Nb|C0sB_Li3=2%yX@j)QrUhRLH}5w_(k$~Wa}3DW=h+k>BGnh!4}`4ZfP zLCrtg^-H9=)FwR0MCbnO=i%x?xy17m$JG%wF)|3!itFF`rWH^Cp71WgWz6yb<(1$G zZ)q|!jZMaGH2{(Bs7k_$;gWv^yyrdG9NX}^(O{V`;6O-~coKJ(x6wP7*VayJfG+eT zDhLhq*RvHk7?jK9x>g(xiT8j-G6_=ofHH2S69qMY$oEpP*#G}#=BC}zkVa;phti2@0 zP()n@E<(`2-Io6!d~JJ{1ZDZ&{@#DNd%?+pBaf=~|9D{GSK}S_cf3l{oeOJd;BXr8 zHRH?RyvcQX*0RRp>4DZ9TToqQ3_V5pCZxx9TTOGz&c(v9XVs4j_N|KEJAYu$`P ztt7R)770id?IhjI?L154J=(jUv{`^mK%2%V(Qsh?C;K}B!fTxnbDcyT;EximjWezo z{Drdey=B_I#QT-iKA+6MLee+DzV|5F^+!iK$ieLWR9Y+QgnH;_d)GmxJU>M4B^ zGKPceGe@4C5YF2cJLrvTWp}U`9gjKI?w?k+T1ou)IY;Vh%9lZ!o5CJ=*wx28s{Qb9 zw&8W$qe{;#H=i?zBKFr9WK66@GBD8XZClp}YP?ZypZ{OkuHGjt_6VHZNa*=4y+kJ~ zM+~^PO65ynol-MDf2?#K`<)55+H3g5;rVaw-GWpx^1&87cOv^adr40((>oZ0fP6&o z@L)c_frgezW!;F)xmH(Ji(;t(^;hyIGt!*zy8pCwEYNAI?4(?XOl^(hGLdXHzU5w( z`C-BQg-y=K;knS3pegx~kQh>2Rt$dr01L?8mLz=jXKQl;gXYZ+bcKZG#kyt^&7C!0 z>=9o-&)C;9{XEAE^$*9T>H*HeAbIO(c187q>63C53m~Yb|DUq11D?wE{Xa%V)+x%V zWQQ_3W$zIULM5pX5~4yJdmJI7lrpnNMG?y06lHIc%3Pt9_*VQ{OZi;w>&*`R5wp7ORXu0a;R-t&_6yDzlNHq2@kJ$}5Xk zxTUr;99U13vuQ)7Az$cJRVGtONy$Uhff3Q|hG1MDAysh~p-1naXVkN2N(>L4H&4Pv zwLhv<0(ktHSml;lVWYADo!5sd?E1pkZI^d`CIXK>iC1OJOwC2f+mAolKI*1Bw!0*5 zn(XDGuhGRT19NtD$Ahtjy1K80kS_smt_`0Q=kJzTwiZGAskN#vp+3MEi9bp%U8--$ zHn~i5(crQwLFwOGd?;+L^2%UuCH%S#x@5s-v(_u~M z*2`Y;$ zen#+^^(0XUp2feTGuD8M@=%ens&1x1QL0%1YB+9nfY81yjN9l)*i9t7YsIZ?;5KS1 zuH^=BQ&im!t@`opf?!R|p@Wd8AQjz2Gz`3s*M?7WWh&V8m+>zpl$!TnZr)Vb^w>Po|ad-mk{)qRuN7;gO)H7g3#HPLn-;#} z7^y*X|B~$b>*K#_f;n)+veoqMZG2>w^TPF2>CS=j^>Dpodb-b>AM9~IpaYm7pL+40 z3eE2vDJgYm-$Ok~n~`tIGG^c!&FopQ~$*E1W;!SW*f&5Q58 zLLAZ6EnDW;+;+nYZ-2yX%nT1t5G$5h4xlx+pSQeKdlW(SPUXmTEax=NJ!wFrkyqN z@``IQYO8(rEiE&+=MZOiCab-@Eu`QtprnzS;!DuSe?Las)hI0cw^-G3+ zW_WYSQ%Axq2QiS2%=h6x7+70wMJkI2+`h`vN-NW0y59ifYaLqk;r2%rX_x#mmooup zeElXrt<#Zg4g`DH4(jm9m$tjO_qgZwBG&xtgI{&=A!TJQ{-hdZ*}-8a^3X6Dc9XiS z`qt)Lham00s`T-}g9m2XTNA-`}RzEd&su>f3X2r0Vezk$^b8!ROn8B1Yv~M!1F0){Y|7aLGFx zGH#z_0nOfgm;;jc{vEL~-mb-N?9mEkbyI9@6=U5Q8N@qh>?c zKumro&!VEP4tu{T_#F;M*C6VdC72@JZQ1tSY4w8gFQFEQj0lJEcWUbWnIu?)!bJqzM56Ng^w-QbI(pqVf8P`g&t*ZC086(!c# z8C%#7#b~HMswe%J-Z$WADjCYEj*A=%Y2k_xYKZY?WWamALu>^}kG2Fcaidg0BSMXR zkGe9_htk!JG4jxS3bl;dHED4&l=Lt(DSS(w+)UAt5_LWWx7E`!7cCQRg%r|G9hh1j zBq{+QPzjiuvkt9W8Y(DPyN0NeM-(E+7brLUO;2U8*;wCxVJHQ`8N8UQ%^{Bc0>YC- zdIu;fzTtiuuY}#TBIhhkwqz*IoH2NRq81Yb>tc6XG!3&Nm1l3;O4Kv|!GQ5rkWEgB zi}SB;yUmSxKM`LDXmyNim{=Cae^XXQ=w;O|Uhn-r`fXxae*W8tpUH*&Fdjq4t~<^} z%iE{)QD>y&M^F%vAb80FNuwz8+fGGa6^Z0Kxq3Uu1RXA@S3goHd@X`N%@iSbG9ep5 zORr1xPUm&m^>u#xmTk|vb7>|Z)$KkP2qbh|<}56vL=i8HyiEKrI{>@NXt*w2x+K=b z?|Zc@zu2<(ii8ar#tPzM)Wr*&H84pXVo#zGw8zDqreRW!R3(*9IUf>JOD3uVTL5ON zlNpCuMqe?w%v)l#@b0Ujo1@?(kS2oo%v<*aW~bf?Z3b^oOZ%Uyk7g2WFC)+X2;sB? z04biQ_muUXQ;`G-(t((N42oM*4~_HRM{QYHyaFyQ)VjOrzGjn^=!D|hSWKg&hs!%)L#{UJ@%lN+J1HG zwA@fG9xq$SKGMKlAtZ9F-60N!a93j@4?WC5h(C&!%gXAGv@eZPb-UQlk6VKBGorh9 z18!>ML(rCuiKe;tRRz2RlGCRDr+%WuR!4vORIyj3Q8;RKJn0nMp52@a|K=-r9zign zf+DUrmLfm|n1{7Pr}cYpwB%fWOY61g6TQqQFDxVHw3yT(LQ?77sY{w2JK;Y$B*ilJ z6eTCszbZ@JjNC(hut^csy2nhWZ*Dl5J0%*arqb1&nVuOd>>qQr>N;jc4ja$jn4rJ# z`J1+RKP2IWAB(PVD>TqXUH>jQVZRYet3z4xyS@)eS7@GF_(q9&yf~+IzWY(s%Tkf*4>h^TYHa!ej8OJ zr`NI;F(b2mOmnHw#m_`cI*zT2%vebOfB6!cNg5{2j`5bb0>Gs}19Tyn2yv-HW3(?- z0(K1&*<*?!B=FFa9>BOfgA|`{1#xIABSB`5l5_L(>VlxkNxSlW{q~;9tF)8Fnf4z) zX|eA)7LyDw{If|`y`df|iW6G8UBw%&BxdKgFQYceJgl_l2&;V!yXcNrngrwEiLk*qnwHLAeH2X<G7lWQcLasX%;ERG>WKXjP>Dz7CO=r;*!tfH3#Q+8MR8NFh>9WL4rVGz8lr*l{3@`vhOdRtb#5>d@# zdy-z+Bk2AA;eu>E=DWJOE|aMQxZz9i1r_T*Ltbmd8&xQXi-&t7m9|l0mcZKoZEe!h zMd!VdLdJ-~Av!;kUmpdLpl9`&`j_A&f!}KZ!UfHUWvJx5pAI`E9)kS1h5oWtv6lnT2g~kodia~hFvC1{zyzVQYj$la?8`wrHCy{U#EYENQMjFm`!Ao z{Ip{hV&ol3>swX(5#X@m-5f~;=ke?BFOaCP%Hvj!_n#k5CQ-jl*4~*jtAqAgLjf0% zfL9jdpRVPMmIfYaSb!ke7=t`}q0GVDXub%+6vFHZyOfd)wHJ+x`M>zlyVDTM6!HPq z1Kx>lGFK-<_Hh5ooY;N{u$^hT+VTX`gG9I}zFiPfV~84XFXS@7oO%7~5X&fhbJkM~9(3+| zPE7FW2PYmH8YG8g&ajXnH^cvvugMNSZ@>gOblm~3yQ!vtRKNd^C;+)AP)svjK+wkO z?vjfKfN&N{uy)F#T>A1^{}?PI zV(JeqGyV}3T%W-{x>u7jo_FtRC9JNl;(jToqLOn<-Jx)s^`k>fpQNQh-B^3Sq(O~o zFKRK_Jh0*F*B_1vvToL3R$y_j6e;JvxBW2X%V|<`fWT&15R%bNd7z(bny`U8}#Y=ZgEU%ZAGnEuWOJQR)q<4@IKpa}I6h?JP zox@fi*m0H}tPGKIT+gT>K1351*Hmfzl@4#CcO|olPV#JHrEzm|f2EDevln#pGRtp} zbc-Ew)=OaD4jp;=Y-)|@#9&Liy8>4=K=ZDduSa-!VGb*4Aak^@(K0j64j%V)-pnZY zqW$7mWv*q|t^gUK`v;VZGhqSn5nocYtbB7#uPp!Vhl@{PNQQRNKt^p@!mhr0p(Eva z0Kr(%SG@sub1L#hMF?r!(LZ$j6eLsx)F0!jH^0pWrr{#5RkZ4FPW;I)>biLp;&nFh zw;J(VeIgBGuyk=|q{xj0pm)Jc#1X^%_ zg!|(^&i#`lgDEL-Fav}>CgOTEa}i`SL&GvZpx3#pL9_V_D!LWBy`e>|C#RgdETV*$ z@f5OS-+RWF9N|tdLBl)(P1f%=gZY#Ea(DPTVE2 zr4VNOF!c50s8-X(^*KDWuBZ9nde7nKmnV0Pb|C>*|4!)L8xux}eDHOF4Z^_0fM(hUTJ0LAX9c^Xne z1?Z})dz21kdDVx#y`$$h&IYTRF4j^;kc;X&q_^<3{an5+Gr$G-`d#$$V)wurW(f#J zK3=)p)jl|=4GV?ZH2wxvziDrp$u?dfVcHiKppsg=$cb=%AKNLBiq%$gX9q@YFEDc^ zzo#NZN5?ih+({dAwm($`GXaGYN|apEp=T#vf;LV@@S7@Du<}n>PspE4B15Wqf7eH; z)xdWjw!Se7lltVqm`AGviO!kP??|n-?HJWw5k%0OXV&<~g%5`G_#$l8S zd!m?m1-i~PzVM}nT0udcxX*Dj$eUc+GdEd9bp{)M7V>8^r2`TF1C^{<+Vd}DITw&XETcjH+rY4ubVJTVpI$QP-< zi>K>=AUi2(9)EBSd9#CD%*5$P7K#%1#rYHHNsWg3H?){~65~+wy+WFci;JIs6?*Jf zY!BXB?Q>(QfbJA)@|b(yr#dVKJZFTtsvi(G>DXOwx4$|UwhOIkdY{VhB)v}#v}7-w z*0=?vhyjgNT{hGbA5f4XDG)DPpic_l)J`nd1#Oc+k`>uYzLgkNhN?FPMcGw9$8S;~ zDDMAIAi$kTko|&^3WC^iqx|#T4w;e&!c`Bn*uQmEnn|2F)E%IPAKKtq2)M95-!~|~ z{;KEhxGQ{VanD2hKcYej4zFNE9_0PznvY0_3sn3`eLa{Uh;gl*-voT$-?|p7pTDMk zh5|v7KrG#-GOOr}aZ{HtBRhSWUgZAsGrsj$kzkr55cF;B0l5B)ABhMer(8O8rC@3T zN@S!GW4;8AL{h?m1uQf{hwb7_9P|Q2DFOAwK&k1&{^s}#2+}9>AA;FlwgZ^G$>t2M&!A9+vM^rG_qKIiDM-MR)VmO4EY?+y z#B|RCg3dc6d5PH=tu{vQ+R$tWVq4f$DLfkF>vn0lG2ed#EcEG%5r zg}*2V#6}%);e}BS#NAg=HQaSFW{$j%43*L=5~|RbH#`YfUj|S8)@iUQ{TPbZNISX+j)9HeHV+O>qcTH-hv_YehSWO{lxr6%px zoMZ(<=@>{UdIQLtsK)&Wa`RkylQ}F|VR-qJA*FycY%7)d4%C(E-R{xtRH&m zj(?vaT9i-wz0;HbDWuc1WW%ytqsUJDRmDUYR6mjGyY@{ho_@QIKQHtY>*(3v$%Cm> zEpq_avS)A2J?AS=lHPh(zYa-;8sX3`HRayafCTq(cL`yYII)^-vefqI(bxR$Q$6NC zcf?0jha3i4P$;Xxw0^Nj@Z9g*5XhY1(YH81I$NjgrUCUU)1B`6S93Ntk$%>yd6}*m zeNuLBU=4`3b8svr zmC3eP-Mi-o3g&~emXeo*)M%rNTH-@Iy6ze2>M{_n<_#Bpw(BZ^4ueyQSZv?MOG4p< zDRCuNdB6qVe<$O6q({Mn2j#i%W;gJc0yYt3{a8=#y*sd;r)6ewrw;12K@;AmYtR7a z)_QC=r3sb%v0WnAJt}ZaO3%*%ZF<+m)*p^GmR1Y61BI>%OM&a@`CS_&%RZ#|F?j+w z8rdPeN^;7szo19(Eb4Iw+ zIO0d22Ob5(gM15wvWy2dR4TYw_?Blj^wHLsRcfu#=GHV#1_H1eNnho9?D%fqVz|v`c z8F-UC@9m7-E=GC!h7hy$uOzk%;*Gbr8-$hZL=I3w)o|VM%e=T>Qg4plku@6zJ7%jK=`BV z1t9ncgP=t?QQ-R=mITNSL)QC9&Qw+Wl`7g3!Y5Tz*i5nKCD{Yc-^0YL4btT3?@X$C zPWqcL7$&;JRlS#x6r+sWXdA^^6FG>YwiKFN)shQ~H5Ne?%_dhVJ&*!{9df{L2Q=)g z@_;NNQn3#^uyV+z^y7UsFAk93X!dqG^>%mnPEE0>7))T^C5g_RQas9@q`L{T>+b9s zn!^vLps9ZR*pHCkwUgS4BWxe=O-wzg5i#})kJHW|Npn8*RVWooVG}$^UV5`@1rp49 zy|~3I->oXdRyQ}T3A^ct$0lp24*RJM3Zp30S&z>rqzkh$Gs<5Y0kUCCM;1!Sp=ocv zg@-7+k@XoiKZmteuAbeF1TTfo*8J}~<=&6N~Aul!v}M9jZ6E+FbytyRxE^Pov&+bWKrSe<)tjsqdpBw0FNN3DDu^=q6k?p$46 zT_|7wd?aLbc&CWZA+aH`v0;5(UCYg~#Ep+_nWCxMaS9&O?l|JZ2V{$dok2@tx_NSI zLz3aXYt^qPxm493MR_s8Qr@7((75E zoc+rLSwlFuD=P~R1M4!l=xH%QUGtO!HkjHQ;t!$GY;0^SDm0-}OH(@P-g{XsE(u4~ z)g7%ncP=jOOt7PagOd}Jfs`V~RvF)+xIWuaUH$65`JylF04?*$%evtj^w~n!tWqA* zF~Ccx-psBzmeXUfP`j1XTW6#@WO7wGW|+yWF5AH2%E>o8S7?67tc~aGAN6%cUx9Un zlZu2P8Gn=4sj1p!n~yz~qCTH_<{py)v<>*zHfu%UR~u7-?bf#YBV_$j_T!yrYMwe2 z5?lK_h%+wqwE7>e30`Q+pS=uRcb++in5rrFN zBTtutuw_~J#-1G3<2U4R+go*^{KU@w&=cj0jXm}%0a^VX1zj7g1~*~ND5u1(!+s6~ zS*CvG>+xLTOPF^yqZ18P?{AUvfQms`$JBgZtI1V8!#oabLgRUd@41%4gIbG+H<3NPLUlKB}Ev9Ga6AmQ|J}Ve-6|62O@$@r^1$+2*hQk4iz0I$!6)op7d^q&H z3OMTxDcm+QSM$z$Z1fck1S`nwXC?huoQ!G*eZQkacz;86Aam+~d|p-oK7+Wq0)1v% z5)`v$T%DY>OGDO*KpZ%G{`_#gH}GJE#dkjUK-IUPpTrwOdX&x%#T8tS!xE`G?L!m< zQR;rt&#@+FZ| z!?K?9iwT3R3rj`?bJyU^Rln_GcnAlNwKfZW1^mySn&;2f#>=fgpiWs{UiO$*EVcddX?<~G z?8TkkU{%Jqs&t0fqq_r(($W|W4;=Sx6%*#+;hFpbS$;cD61O!n4`(x6c#1Ec$xOn@ zEuGo)fBN(gs0jUEe?03Ckq&!1~*qJ~H1NxSR?Xx~~+ z!M5j?objH8MSD9ttpsT}Cu(Zjv#i311I<533!RD~cx7klYHx zOnWv`*3!~ki=R@Bn{vU7k`UzwoMWGj-O8;ZQ-bDF|HjzpIHi2P5#Ex)V_7S-!)1KQ z5;vH!^kmDuxsc)LErELA6#ygyXA6iq$)I|5&<*eBcuLW2#XzsyUqQ13?(cg2dz{gF zeeNb6BqV+3KLb&ZO?)nrCWDY(#_U9N;E>m)r%&(*;Jj zECNuyb6Fm3S2jDu?|8Snr`9m%x)|Nn9-Y_`31GdZ*w#WM2tnON6HnOnUdf%$@Tbr=ST zTxv;C9R@ikiE3eW&~Yl&4g(oKlGx#rmD5|7$5^$n+P|@{(Osa}d_E`jR#xVX#m?Y_ z?J>bDgY?HsP8I9-0{jo1B@jpt9`5TK6clv+v5d8WRcSKXhjfOlnC6UZw_s#AQD2E8 zGERPd#;C%kK5RBO7us+uNJ~r0%L@yOYsO;^a&RQPc=0C9%DOqO$cT`Jx(PhQ)&x08 z188e_+`WEj_w=>W>0rNUJ~9s6z}FX0x$q!*DO1L55z?mYYa|AsIsT zmql%E)2?Y^VwzxKG^`;ax@ymCu*Ne@bC5wH^9x?5;gIJ$~o zBnIM6lexW?^_-r){b(vP55W<*44_r+d*^?p<(`P~AKy$L=)s{QW=qP7YD5)G-CKn@ zR^8dwA~|KeNrlaH4)v8>o1_o>u$vgB@%%~#$%ylUAy!V%E@-JjL zpd%{qU-7?^PMyNLFZsMwE&%=UK+h>T`t%=>74-6nsZS3@+E2v6L6Gnh331Ezhj&Vx zoX2=j=BkmHNd0E*?f9^;u;^&msSI&>>^^KMJa>^r?c#a94!v@_)MNo#+CbXC!28e= z;{Lp)$srJmOPMxAW~RbOs8Zgg|!} z^p#e-!-n0Po0~Sgi6jVHH^08fy0Ns~0;b?H9VSP88BXrg(9)`_MJGf=!+Y>XmQZd# zD=d`CaWNPYro@uI5AmhB`kFbpl2=|z%6WXYhxE(K6J&-L!#Z=tG_HL0ZKOSV^ysN7 z$@^^2{g!n>6y8ry&lnH=v2&Oc5@Z}UwjR=L_m1p4A}$O9ZxqHv#m?^JLz0go#$u#E zCGR%3*ir^CuN;MH-KTa=Q?seK=_HrEyPf*(zpg|3wYkm3w#<;aZYNMLtu5u|_S!UD z5*2Ma+L-7=(yTBtWFEHf3kviWH=5(ubG+gc1*R+u_6 zfX16wXGqQyCyOg54u5{ELR0i|J>1K>E*irn`tXPd$;6N#tdeBVM> zt5>f^M@J#vgt6G)ycv=#aM$JO8>LVI1PQnaipK2E4v+Fs{yZHI4?^U&a9qs!6!-WR=gc-q?%sqh$3+^kL1?o+F)&vyTL$BFpaXtdwc?TU&Dd7etH zv1OqmJB(7>IaTG$R4}coA0V4>aRE|*-{s}weKCCg6Yu#?ED){3&FUIrtn$YD;jm}g zz&{3dI==4KC6*&6c7ARYWw#no!TfeYZ@zoO)xCh)zE$jMTgngJ3pd#j#1TZ#WI<9E z1{BY`4A aY1ivXgz8>@gzQ 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 z

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 literal 0 HcmV?d00001 diff --git a/book/1_gradient_divergence_curl/figures/crossprod.png b/book/1_gradient_divergence_curl/figures/crossprod.png new file mode 100644 index 0000000000000000000000000000000000000000..dcb2e776bdac0559a3efa093074be716d94b752e GIT binary patch literal 21989 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 FO#s{@0_p$& literal 0 HcmV?d00001 diff --git a/book/1_gradient_divergence_curl/figures/cylsphere.png b/book/1_gradient_divergence_curl/figures/cylsphere.png new file mode 100644 index 0000000000000000000000000000000000000000..2837e0532fe3cf66ad55c9d67ec41ccc0b6eef79 GIT binary patch literal 96170 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≪VZe{a}v^^~- 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 ZH~ZJ^{b&9n?C~^^O`fiPF6*2UngH5b-UR>v literal 0 HcmV?d00001 diff --git a/book/1_gradient_divergence_curl/figures/dcpoth.png b/book/1_gradient_divergence_curl/figures/dcpoth.png new file mode 100644 index 0000000000000000000000000000000000000000..48f0a9cac48e0b0a267f60d5b813449d7efa767e GIT binary patch literal 314878 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缼PNxJ1*&fC_* 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�Q-Z60A;+`LGPA2u;OK<47g`ef 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 literal 0 HcmV?d00001 diff --git a/book/1_gradient_divergence_curl/figures/dcpotv.png b/book/1_gradient_divergence_curl/figures/dcpotv.png new file mode 100644 index 0000000000000000000000000000000000000000..1a10d17c8aae92f8766096573fdba8995114e54f GIT binary patch literal 219574 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 AX6*+d)UMX`etpl!`?-pU7#glLCy5H^JIOaHs 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 Iw7C7h02voSLI3~& literal 0 HcmV?d00001 diff --git a/book/1_gradient_divergence_curl/figures/rotCartframe.png b/book/1_gradient_divergence_curl/figures/rotCartframe.png new file mode 100644 index 0000000000000000000000000000000000000000..3bdd9f59ac3697cfeb285e671b0d722f88c617e8 GIT binary patch literal 92088 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 GC;tnLcN`)B literal 0 HcmV?d00001 diff --git a/book/1_gradient_divergence_curl/gradient.md b/book/1_gradient_divergence_curl/gradient.md new file mode 100644 index 0000000..3823a25 --- /dev/null +++ b/book/1_gradient_divergence_curl/gradient.md @@ -0,0 +1,159 @@ +# Gradient of a scalar field + +Let us consider a scalar field, which is a function of the three spatial coordinates and possibly of time $t$. We write it as $p(x,y,z,t)$ in Cartesian coordinates. A scalar field quantity has a value represented by a single number at every point in space and at each time instant. You can think of the temperature in the room, or the air pressure in our atmosphere, or the density of mass inside the Earth. + +Such fields possess iso-surfaces. An **iso-surface** is the collection of points in space where the field has a constant value. The gradient of the field quantity points perpendicular to that iso-surface. Let us investigate how that result is found. The gradient is a partial differential operator given by + +$$ +\nabla = \left(\begin{array}{c} +\dfrac{\partial}{\partial x} \\[2mm] +\dfrac{\partial}{\partial y} \\[2mm] +\dfrac{\partial}{\partial z} +\end{array}\right) += \hat{\boldsymbol x}\frac{\partial}{\partial x} + \hat{\boldsymbol y}\frac{\partial}{\partial y} + \hat{\boldsymbol z}\frac{\partial}{\partial z} += \hat{\boldsymbol x}\partial_x + \hat{\boldsymbol y}\partial_y + \hat{\boldsymbol z}\partial_z . +$$ + +We use the short-hand notation for each scalar partial derivative, e.g. $\partial_x$ for the derivative with respect to $x$. If we apply the gradient to the scalar field quantity $p(x,y,z,t)$ we obtain a vector field quantity that we can write as + +$$ +\nabla p(x,y,z,t) = \hat{\boldsymbol x}\,\partial_x p(x,y,z,t) + \hat{\boldsymbol y}\,\partial_y p(x,y,z,t) + \hat{\boldsymbol z}\,\partial_z p(x,y,z,t). +$$ (eq:gradp) + +## The gradient of the distance function + +To get an idea about what this implies, let us consider the position vector $\boldsymbol r$ introduced with the Cartesian reference frame. The vector $\boldsymbol r$ is the position vector of the point $(x,y,z)$ in space, which we write as + +$$ +\boldsymbol r = x\hat{\boldsymbol x} + y\hat{\boldsymbol y} + z\hat{\boldsymbol z}, +$$ + +and its length is given by + +$$ +r = |\boldsymbol r| = \sqrt{x^2+y^2+z^2}. +$$ + +The iso-surface for $r$ has the shape of a spherical surface. We now evaluate each term in the gradient. We begin with the derivative with respect to the coordinate $x$ and obtain + +$$ +\begin{aligned} +\partial_x r &= \frac{1}{2}\frac{1}{\sqrt{x^2+y^2+z^2}}(2x), \\ + &= \frac{x}{\sqrt{x^2+y^2+z^2}}, \\ + &= \frac{x}{r}. +\end{aligned} +$$ + +We find similar results for the derivatives with respect to $y$ and $z$, and put them in the vector expression such that we end up with + +$$ +\begin{aligned} +\nabla r &= \hat{\boldsymbol x}\,\partial_x r(x,y,z) + \hat{\boldsymbol y}\,\partial_y r(x,y,z) + \hat{\boldsymbol z}\,\partial_z r(x,y,z), \\ + &= \frac{x\hat{\boldsymbol x} + y\hat{\boldsymbol y} + z\hat{\boldsymbol z}}{r}, \\ + &= \frac{\boldsymbol r}{r}. +\end{aligned} +$$ (eq:gradr) + +From the final expression, we observe that the result is the normalised distance vector. This is what we call the outward unit normal to the spherical surface. It points away from the origin of the reference frame. The physical interpretation is that the gradient of the distance to the origin of the reference frame finds the direction in which the distance increases the most. The vector is placed perpendicular to the iso-surface of the function. We investigate whether this is a general property of the gradient. + +Now let us take a different distance, namely relative to an arbitrary other point $\boldsymbol r'$ in space. In that case the displacement vector is given by + +$$ +\boldsymbol r-\boldsymbol r' = (x-x')\hat{\boldsymbol x} + (y-y')\hat{\boldsymbol y} + (z-z')\hat{\boldsymbol z}, +$$ + +and the length of the vector is equal to the distance $d$ given by + +$$ +d(x-x',y-y',z-z') = |\boldsymbol r-\boldsymbol r'| = \sqrt{(x-x')^2+(y-y')^2+(z-z')^2}. +$$ + +Similar to the previous result, we now find + +$$ +\begin{aligned} +\nabla|\boldsymbol r-\boldsymbol r'| &= \hat{\boldsymbol x}\,\partial_x d + \hat{\boldsymbol y}\,\partial_y d + \hat{\boldsymbol z}\,\partial_z d, \\ +&= \frac{(x-x')\hat{\boldsymbol x} + (y-y')\hat{\boldsymbol y} + (z-z')\hat{\boldsymbol z}}{|\boldsymbol r-\boldsymbol r'|}, +\end{aligned} +$$ + +which we write in vector form as + +$$ +\nabla|\boldsymbol r-\boldsymbol r'| = \frac{\boldsymbol r-\boldsymbol r'}{|\boldsymbol r-\boldsymbol r'|}. +$$ (eq:gradd) + +We find again an outward unit vector, pointing away from the point at $\boldsymbol r'$ and perpendicular to the spherical iso-surface. + +## The total derivative and the direction of steepest increase + +Now let us consider a field quantity $p(x,y,z,t)$ and assume we analyse this function for a single moment in time. The gradient of this function is expressed in {eq}`eq:gradp`. Let $\mathrm{d}p$ be the change in $p$ from a point $\boldsymbol r$ to another point $\boldsymbol r'$, which means that $p(\boldsymbol r)=p$ and $p(\boldsymbol r')=p+\mathrm{d}p$. We do not specify where $\boldsymbol r$ and $\boldsymbol r'$ are located, and they can be on different iso-surfaces or on the same one. + +The change in $p$ due to a displacement in the $x$-direction from $\boldsymbol r$ to $\boldsymbol r'$ is given by $(\partial p/\partial x)\mathrm{d}x$, while keeping $y$ and $z$ constant. Similarly, the changes in $p$ due to displacements in the $y$- and $z$-directions are given by $(\partial p/\partial y)\mathrm{d}y$ and $(\partial p/\partial z)\mathrm{d}z$. Hence, the change in $p$ along the vector from $\boldsymbol r$ to $\boldsymbol r'$ is + +$$ +\mathrm{d}p = \partial_x p\,\mathrm{d}x + \partial_y p\,\mathrm{d}y + \partial_z p\,\mathrm{d}z. +$$ + +We can write this expression as a scalar product of two vectors, + +$$ +\mathrm{d}p = \left(\hat{\boldsymbol x}\partial_x p + \hat{\boldsymbol y}\partial_y p + \hat{\boldsymbol z}\partial_z p\right)\cdot\left(\hat{\boldsymbol x}\,\mathrm{d}x + \hat{\boldsymbol y}\,\mathrm{d}y + \hat{\boldsymbol z}\,\mathrm{d}z\right), +$$ + +where the symbol $\cdot$ is used to denote scalar multiplication of two vectors. We recognise this expression as + +$$ +\mathrm{d}p = (\nabla p)\cdot\mathrm{d}\boldsymbol r. +$$ + +Suppose there is an angle $\psi$ between the two vectors, then + +$$ +\mathrm{d}p = |\nabla p|\,|\mathrm{d}\boldsymbol r|\cos(\psi) = |\nabla p|\,\mathrm{d}r\cos(\psi), +$$ + +and we can write the total derivative with respect to $r$ as + +$$ +\frac{\mathrm{d}p}{\mathrm{d}r} = |\nabla p|\cos(\psi). +$$ (eq:totder) + +The left-hand side of {eq}`eq:totder` means the rate of change along the path from $\boldsymbol r$ to $\boldsymbol r'$, as indicated by $r$. The right-hand side shows that this can never be larger than the magnitude of the gradient of $p$. We conclude that the rate of change is equal to the magnitude of the gradient only if the point $\boldsymbol r'$ is located along the resulting vector after taking the gradient of $p$, because then $\psi=0$. For all other locations the rate of change is less. We have seen this when we evaluated the gradient of the distance function $r$. + +Now we have found that the magnitude of the gradient of a scalar field quantity is equal to the maximum rate of change of that field quantity with respect to position. What is left is direction, which is relatively easy to understand. It is clear that when the point $\boldsymbol r'$ is on the same iso-surface as the point $\boldsymbol r$, the rate of change is zero. We investigate differentials, which means we look at points $\boldsymbol r'$ that approach the point $\boldsymbol r$. The rate of change of the function $p$ is maximal when the point $\boldsymbol r'$ moves away in the direction perpendicular to the iso-surface. If there is a part of the path from $\boldsymbol r$ to $\boldsymbol r'$ that has a component along the iso-surface, there is no change along that part of the path, which would reduce the rate of change. Hence, the gradient results in a vector that points along the unit normal of the iso-surface in the direction where the rate is positive. We can express this as + +$$ +\nabla p(x,y,z,t) = |\nabla p(x,y,z,t)|\,\hat{\boldsymbol n}, +$$ + +where $\hat{\boldsymbol n}$ is the unit normal vector on the iso-surface pointing to the positive rate of change. + +:::{admonition} The gradient in words +:class: tip +The gradient of any scalar field quantity $p(x,y,z,t)$ finds the direction in which the scalar quantity increases the most, for a fixed moment in time, and its magnitude is that maximum rate of increase. +::: + +## The gradient in curvilinear coordinates + +Earlier we introduced the spherical and cylindrical coordinate systems. We had to look at the rotation matrices between the coordinate systems to be able to move back and forth. It is now time to generalise our notation of the gradient such that it can be used in spherical and cylindrical coordinate systems as well. Let us write + +$$ +\nabla p(x,y,z,t) = \sum_{i=1}^{3}\frac{1}{c_i}\frac{\partial p}{\partial x_i}\hat{\boldsymbol e}_i . +$$ (eq:gradgen) + +In this expression the coefficients $c_i$ are scale factors, the coordinates are $(x_1,x_2,x_3)$, and both depend on the coordinate system we want to do our analysis in. The base vectors $(\hat{\boldsymbol e}_1,\hat{\boldsymbol e}_2,\hat{\boldsymbol e}_3)$ were introduced with the coordinate systems, and we use them here again, but we make them depend on the coordinate system as well. + +In the Cartesian frame these would be $(x_1,x_2,x_3)=(x,y,z)$, $(c_1,c_2,c_3)=(1,1,1)$ and $(\hat{\boldsymbol e}_1,\hat{\boldsymbol e}_2,\hat{\boldsymbol e}_3)=(\hat{\boldsymbol x},\hat{\boldsymbol y},\hat{\boldsymbol z})$. Now, in spherical coordinates, we already know all the ingredients, so we can fill them in. We find $(x_1,x_2,x_3)=(r,\theta,\phi)$, $(c_1,c_2,c_3)=(1,r,r\sin(\theta))$ and $(\hat{\boldsymbol e}_1,\hat{\boldsymbol e}_2,\hat{\boldsymbol e}_3)=(\hat{\boldsymbol r},\hat{\boldsymbol\theta},\hat{\boldsymbol\phi})$. Substituting these in {eq}`eq:gradgen` results in + +$$ +\nabla p(r,\theta,\phi) = \frac{\partial p}{\partial r}\hat{\boldsymbol r} + \frac{1}{r}\frac{\partial p}{\partial\theta}\hat{\boldsymbol\theta} + \frac{1}{r\sin(\theta)}\frac{\partial p}{\partial\phi}\hat{\boldsymbol\phi}. +$$ (eq:gradsph) + +## Exercises + +1. Evaluate $\nabla|\boldsymbol r|^{-1}$, $\nabla|\boldsymbol r|^{-n}$, $\nabla|\boldsymbol r-\boldsymbol r'|^{-1}$, and $\nabla\left(|\boldsymbol r-\boldsymbol a|^{-1} - |\boldsymbol r+\boldsymbol a|^{-1}\right)$, with $\boldsymbol a=(1,0,0)$. For each result, plot several iso-surfaces and plot the vectors that correspond to the gradients. +2. Instead of taking the gradient with respect to the point $\boldsymbol r$, we can take it with respect to $\boldsymbol r'$, which we write as $\nabla' = \hat{\boldsymbol x}\partial_{x'} + \hat{\boldsymbol y}\partial_{y'} + \hat{\boldsymbol z}\partial_{z'}$. Evaluate $\nabla'|\boldsymbol r-\boldsymbol r'|^{-1}$ and express it in terms of $\nabla|\boldsymbol r-\boldsymbol r'|^{-1}$. +3. We have seen that the outward unit normal of a spherical surface around the point $\boldsymbol r'$ is given by $\hat{\boldsymbol n} = \nabla|\boldsymbol r-\boldsymbol r'| = (\boldsymbol r-\boldsymbol r')/|\boldsymbol r-\boldsymbol r'|$. Use your understanding of the property of the gradient to explain why $\hat{\boldsymbol n}\cdot\nabla|\boldsymbol r-\boldsymbol r'|^{-1}<0$ for $\boldsymbol r\ne\boldsymbol r'$. +4. What is the relation between $A_r,A_\phi,A_\theta$ introduced in the exercises on coordinate systems and the scale factors $c_i$ here? +5. Determine the expression for the gradient in cylindrical coordinates. You can use the coordinates $(\varrho,\phi,z)$ to avoid confusion with the three-dimensional radius $r$ that is used in spherical coordinates and represents the distance between two points in 3D space in general. In cylindrical coordinates $r=\sqrt{\varrho^2+z^2}$. diff --git a/book/1_gradient_divergence_curl/intro.md b/book/1_gradient_divergence_curl/intro.md index 491c78c..c653859 100644 --- a/book/1_gradient_divergence_curl/intro.md +++ b/book/1_gradient_divergence_curl/intro.md @@ -1 +1,95 @@ -## Introduction \ No newline at end of file +# Introduction + +Mathematics is the language to describe physics, and physics gives the empirical content consisting of experiments. Mathematics is grammar, the model is a simplification that is meant to understand a measurement. The model states *if $a$ then $b$*, while the experiment states *if $A$ then $B$*. If $b$ matches $B$ to our satisfaction, we adopt the model; if not, we reject it. But even when adopted, we must continue to scrutinise the model, and later an experiment will come that makes us understand that the model was adopted earlier but needs revision. + +Scientific progress is made through doubt. + +AI changes the direction of knowledge: not any more from rule to reality, but from reality to rule. The data are used to understand and to generate a model. + +Physical objects can be described in a quantitative way only with the aid of mathematics. In classical physics, all physical objects are geometric objects. The course *Fields and Waves* combines the physics of fields and waves with the mathematical tools required to describe these phenomena. The course enables students to develop essential understanding of the physical interpretation of mathematical formulations. Examples are radar waves that are used for earth surface and subsurface observations from antennas placed on satellites, airplanes, and close to or on the ground surface; sound waves, electromagnetic diffusion fields, electric and magnetic potential fields, and the gravity field to probe the earth's interior, the surface and the atmosphere. They are used to characterise layers and objects in terms of physical and geological parameters, and to monitor dynamic processes as well. The sources for these fields can be natural or anthropic. + +## Dimensions and units + +Seven fundamental quantities, or dimensions, have been defined. They are *length* ($L$), *time* ($T$), *temperature* ($\mathcal{T}$), *mass* ($M$), *electric current* ($I$), *amount of substance* ($n$) and *luminous intensity* ($\mathcal{L}$). Other dimensions are then secondary and can be written in terms of several or all of these seven. Electric charge has fundamental dimensions $IT$ and the fundamental dimensions of electric field are given by $ML/(IT^3)$. + +Dimensions must be given a value to work with them numerically. For this the international agreement is to use the so-called metric system, and the present-day variant has the seven fundamental units that correspond to the fundamental dimensions. This system is known as the SI system, from the French *Système Internationale d'Unités*, known as the International System of Units. In this system, the dimension length has unit *meter* (m), the dimension time has unit *second* (s), the dimension temperature has unit *kelvin* (K), the dimension mass has unit *kilogram* (kg), the dimension electric current has unit *ampere* (A), the dimension amount of substance has unit *mole* (mol), and the dimension luminous intensity has unit *candela* (cd). These units are defined as follows: + +- **Meter** (m). One meter is equal to the path length travelled by light in vacuum in a time of $t = 1/299\,792\,458$ second. This defines the electromagnetic wave propagation velocity in vacuum as $c_0 = 299\,792\,458$ m/s. +- **Second** (s). One second is equal to the duration of $9\,192\,631\,770$ periods of radiation corresponding to the transition between two hyperfine levels of the ground state of cesium 133. This is now known as the atomic clock. Atomic clocks are accurate to approximately 1 microsecond per year. Before the atomic clock the second was defined as the mean solar day divided by 86400, but because the earth's rotation around the sun is slowing down it was regarded inaccurate as a standard. The two standards differ in the order of 1 second per year. Distant fast rotating pulsars are, with their 1000 revolutions per second, a possible new replacement for the atomic clocks and will then yield a standard with an accuracy in the order of nanoseconds per year. +- **Kelvin** (K). One kelvin is the temperature equal to $1/273.16$ of the triple point of water, defining the triple point of water as $273.16$ kelvin. Water boils at a temperature of $T = 100\,^{\circ}\mathrm{C} = 373.15$ K. +- **Kilogram** (kg). For a long time this was the only unit still defined by a physical prototype: a cylinder of platinum and iridium alloy stored in Sèvres, France. In this sense the kilogram was an anomaly among the unit definitions. +- **Ampere** (A). One ampere is equal to the electric current flowing in each of two infinitely long parallel wires in vacuum separated by one meter, which produces a force of 200 nanonewton per meter of length. +- **Mole** (mol). The mole is defined as the amount of substance of a system which contains as many "elemental entities" (e.g., atoms, molecules, ions, electrons) as there are atoms in $0.012$ kg of carbon-12. It is related to the number of particles, which is the Avogadro constant $N_A = 6.022\,141\,79\times 10^{23}$ mol$^{-1}$. +- **Candela** (cd). One candela is the luminous intensity equal to that of $1/600\,000$ square meter of a perfect radiator at the temperature of freezing platinum at a pressure of one standard atmosphere. + +:::{note} +The definitions above are the ones you will meet in most textbooks, and they are the ones used throughout these notes. Since the SI revision of 2019, the base units are instead fixed by assigning exact values to seven defining constants: $\Delta\nu_{\mathrm{Cs}}$, $c_0$, $h$, $e$, $k_{\mathrm{B}}$, $N_A$ and $K_{\mathrm{cd}}$. The kilogram is now realised from the Planck constant $h$ rather than from the prototype cylinder, and the ampere from the elementary charge $e$ rather than from the force between two wires. The numerical values change by far less than any measurement we make in this course, so nothing in what follows depends on which convention you have in mind. +::: + +The other units are called secondary, or derived, units and can all be expressed as combinations of these seven. The International System of Units also recommends the use of abbreviations of units in steps of three orders of magnitude. To take length as an example, it is recommended to use 10 mm over 1 cm. In these notes the SI system is used and the abbreviation recommendation is adhered to. The metric system and its scientific prefixes are given in {numref}`tab-si-prefixes`. + +```{list-table} Numbers in the metric system and their prefixes. +:header-rows: 1 +:name: tab-si-prefixes + +* - Numerical value + - + - Prefix + - Symbol +* - 1 000 000 000 000 000 000 + - $10^{18}$ + - exa + - E +* - 1 000 000 000 000 000 + - $10^{15}$ + - peta + - P +* - 1 000 000 000 000 + - $10^{12}$ + - tera + - T +* - 1 000 000 000 + - $10^{9}$ + - giga + - G +* - 1 000 000 + - $10^{6}$ + - mega + - M +* - 1 000 + - $10^{3}$ + - kilo + - k +* - 1 + - $1$ + - one + - – +* - 0.001 + - $10^{-3}$ + - milli + - m +* - 0.000 001 + - $10^{-6}$ + - micro + - $\mu$ +* - 0.000 000 001 + - $10^{-9}$ + - nano + - n +* - 0.000 000 000 001 + - $10^{-12}$ + - pico + - p +* - 0.000 000 000 000 001 + - $10^{-15}$ + - femto + - f +* - 0.000 000 000 000 000 001 + - $10^{-18}$ + - atto + - a +``` + +## What follows + +The remaining pages of this introduction deal with sums, series and approximations, and with reference frames, symbols and notations for scalar, vector, and matrix quantities, together with the notion of time and temporal variations of a function. The pages after those describe the three main spatial derivative operators — gradient, divergence, and curl — and discuss their physical meaning. Later chapters describe potential, diffusive, and wave fields, respectively. diff --git a/book/1_gradient_divergence_curl/sums_series_approx.md b/book/1_gradient_divergence_curl/sums_series_approx.md new file mode 100644 index 0000000..3306266 --- /dev/null +++ b/book/1_gradient_divergence_curl/sums_series_approx.md @@ -0,0 +1,108 @@ +# Sums, series, approximations + +In all classical physics domains, it is useful to write a quantity as a sum of a large number of terms. In many cases, each such term has a physical interpretation. Often, the large sum of terms can be approximated by neglecting most terms based on physical arguments, and keeping only a few terms as the approximate solution for the quantity we investigate. + +A simple example is position as a function of time. A particle that is not moving has a fixed position and we can denote it as + +$$ +x(t) = x_0 . +$$ + +This expression states that for any time value the particle is located at position $x_0$. If at $t=0$ the particle starts to move with a constant velocity $v_0$, the position becomes a linear function of time. We can express it as + +$$ +x(t) = x_0 + v_0 t . +$$ + +If we take $t=0$ in this expression, we find the starting position $x(t=0) = x_0$. To find the velocity, we must differentiate the position with respect to time and find + +$$ +v_0 = \frac{\mathrm{d}x(t)}{\mathrm{d}t} . +$$ + +As long as the velocity is constant, we can evaluate this expression at any time instant, but if the velocity is variable we must evaluate the expression at $t=0$. Hence, we express velocity as + +$$ +v_0 = \lim_{t\downarrow 0}\frac{\mathrm{d}x(t)}{\mathrm{d}t} + = \left.\frac{\mathrm{d}x(t)}{\mathrm{d}t}\right|_{t\downarrow 0} . +$$ + +:::{admonition} The unit-step function +:class: note +Note that in this expression we take the limit from positive values of $t$ to zero, because the derivative of the position of the particle is not continuous at $t=0$. This can be seen because $x(t) = x_0$ for $t<0$, and the velocity of the particle is $v=0$ for $t<0$ and $v=v_0$ for $t>0$. We express this as + +$$ +v(t) = v_0\, u(t) , +$$ + +where $u(t)$ is known as the unit-step function, given by + +$$ +u(t) = \left\{ +\begin{array}{ll} +0 & t < 0 \\ +1/2 & t = 0 \\ +1 & t > 0 +\end{array}\right. . +$$ + +This function is also known as the Heaviside function, after Oliver Heaviside. The value at $t=0$ for $u(t)$ is obtained by taking the limit on both sides to $t=0$ and keeping the average. This is called the principal value. To avoid differentiating a function with a step discontinuity at this moment, we have used the differentiation in the time window where the position of the particle is continuous and continuously differentiable. We deal with differentiating across discontinuities later. +::: + +Suppose the particle also has a constant acceleration $a_0$. From classical mechanics we know that the position of the particle as a function of time can then be expressed as + +$$ +x(t) = x_0 + v_0 t + \tfrac{1}{2}a_0 t^2 . +$$ + +To find $x_0$ and $v_0$ we can use the recipes above, while to obtain $a_0$ we must differentiate $x(t)$ twice with respect to $t$. Now we assume the position of the particle is twice continuously differentiable with respect to time, and this is true for both negative and positive times but not for $t=0$. Hence, to find the acceleration, we should evaluate + +$$ +a_0 = \lim_{t\downarrow 0}\frac{\mathrm{d}^2 x(t)}{\mathrm{d}t^2} + = \left.\frac{\mathrm{d}^2 x(t)}{\mathrm{d}t^2}\right|_{t\downarrow 0} . +$$ + +It shows the intuitive knowledge that acceleration is in the second derivative of position with respect to time. + +Now, if we generalise this notion, we can think of a position that changes location in an arbitrary way and has many more non-zero derivatives that are all smooth functions of time except across the start of the motion. This is one of the aspects of the principle of causality: a response cannot be present before an action happens. In classical mechanics it means the position cannot change unless the particle is already in motion or a force acts on it, in which case it has a non-zero acceleration. This notion belongs to the concept of the generation of fields and waves and we discuss it in more detail later. Here we state that the position of the particle can be generally expressed as + +$$ +x(t) = c_0 + c_1 t + c_2 t^2 + \cdots = \sum_{m=0}^{\infty} c_m t^m , +$$ (eq:pm) + +and + +$$ +c_m = \left.\frac{1}{m!}\frac{\mathrm{d}^m x(t)}{\mathrm{d}t^m}\right|_{t\downarrow 0} . +$$ + +## The Taylor series + +This series, where a function is expressed as a sum of terms with increasing powers of the independent variable, is called a Taylor series. It demonstrates that we can know a function if we know its value at every point in time, $x(t)$, **or** when we know all of its derivatives at one single time instant. This is under the assumptions that + +1. the function is continuously differentiable infinitely many times, and +2. the series sums up to a finite result that represents the function. + +The Taylor series can of course be used for any function, for any variable, and in more than one dimension. We can therefore write an arbitrary function of position $x$ as $f(x)$ and express it as + +$$ +f(x) = \sum_{m=0}^{\infty}\left.\frac{1}{m!}\frac{\mathrm{d}^m f(x)}{\mathrm{d}x^m}\right|_{x=0} x^m + = f(0) + x f^{(1)}(0) + \frac{f^{(2)}(0)}{2}x^2 + \cdots , +$$ + +where $f^{(m)}(0)$ is short-hand notation for $\left.\dfrac{\mathrm{d}^m f(x)}{\mathrm{d}x^m}\right|_{x=0}$. + +It is not necessary to expand a function around zero, and we can expand it around any point $x=a$. It is given by + +$$ +f(x) = \sum_{m=0}^{\infty}\frac{f^{(m)}(x=a)}{m!}(x-a)^m + = f(a) + f^{(1)}(a)(x-a) + \frac{f^{(2)}(a)}{2}(x-a)^2 + \cdots . +$$ (eq:Taylor) + +We saw for the particle motion that for negative $t$ the particle is at rest and has position $x_0$. The reason is that at $t=0$ something happens and the information is not present in $x(t)$ for negative times. We saw that $x(t)$ changes continuously, but the slope does not change continuously. Functions that have a discontinuity in one or more derivatives are called non-analytic. Taylor series cannot be used for such functions. Until you reach a derivative that is not continuous, a truncated Taylor series expansion can still be useful. + +## Exercises + +1. Expand the particle motion of {eq}`eq:pm` around $t=-1$, using $f(x) = x(t)$ in {eq}`eq:Taylor` with $a=-1$, and explain why it is not giving you more than $x(t) = x_0$. +2. Find the expansions for $\sin(x)$, $\cos(x)$, $\exp(-x)$, $(1+x)^{-1}$ around $x=0$ and determine whether the Taylor series converges. +3. What happens if you try a Taylor series expansion for $\sqrt{t}$ and $1/t$? diff --git a/book/_toc.yml b/book/_toc.yml index 300a786..3b9689b 100644 --- a/book/_toc.yml +++ b/book/_toc.yml @@ -11,9 +11,11 @@ parts: - caption: Gradient, divergence, and curl chapters: - file: 1_gradient_divergence_curl/intro.md - # - file: 1_gradient_divergence_curl/gradient.md - # - file: 1_gradient_divergence_curl/divergence.md - # - file: 1_gradient_divergence_curl/curl.md + - file: 1_gradient_divergence_curl/sums_series_approx.md + - file: 1_gradient_divergence_curl/coord_sys.md + - file: 1_gradient_divergence_curl/gradient.md + - file: 1_gradient_divergence_curl/divergence.md + - file: 1_gradient_divergence_curl/curl.md - file: 1_gradient_divergence_curl/labs/week01-grad-div.md - caption: Potential Fields chapters: From 90a384668945cc34308454f4c7cfa6c0173f3952 Mon Sep 17 00:00:00 2001 From: ARS183 <1028762817@qq.com> Date: Tue, 1 Sep 2026 15:26:58 +0200 Subject: [PATCH 07/17] Tighten the prose of the Week 1 lab --- .../labs/week01-grad-div.md | 425 +++++++++--------- 1 file changed, 211 insertions(+), 214 deletions(-) diff --git a/book/1_gradient_divergence_curl/labs/week01-grad-div.md b/book/1_gradient_divergence_curl/labs/week01-grad-div.md index 92f9a23..12a4779 100644 --- a/book/1_gradient_divergence_curl/labs/week01-grad-div.md +++ b/book/1_gradient_divergence_curl/labs/week01-grad-div.md @@ -19,40 +19,40 @@ mystnb: :::{admonition} Computer lab :class: note -A practical companion to the lectures on the gradient and the divergence. Each task states a physical question, gives you the steps, and ends with a self-check you can run. What we supply is the *plotting*, in a module called `fwtools` — drawing a transparent isosurface teaches you nothing about electromagnetism, so your time goes on physics instead. +A practical companion to the lectures on the gradient and the divergence. Each task states a physical question, gives the steps, and ends with a self-check you can run. Plotting is supplied in the module `fwtools`, so that your effort goes into the physics rather than into rendering transparent isosurfaces. ::: ## Learning objectives By the end of this lab you should be able to: -- **Truncate a series and know what you lost.** Sum a geometric series, approximate it by its leading term, and say how many terms buy a given accuracy — and where a Taylor series stops working altogether. -- **Read a gradient off a picture.** Show that $\nabla r = \hat{\boldsymbol{r}}$, that $\nabla f$ is perpendicular to the level surfaces of $f$, and that $dp/dl = \lvert\nabla p\rvert\cos\psi$ — so the gradient's magnitude *is* the maximum rate of change. -- **Turn a potential into a field, and a field into a survey.** Apply $\boldsymbol{E} = -\nabla V$ and Ohm's law $\boldsymbol{J} = -\rho^{-1}\nabla V$, and map the potential and current density of a two-electrode DC resistivity measurement. -- **Distinguish "arrows spreading apart" from divergence.** Compute $\nabla\cdot\boldsymbol{v}$, justify the answer by flux rather than algebra, and find the only radial flow that is incompressible. -- **Use the divergence theorem as a measurement.** Verify $\oint_S\boldsymbol{v}\cdot\hat{\boldsymbol{n}}\,dS = \int_{\mathcal{D}} \nabla\cdot\boldsymbol{v}\,dV$ numerically, and explain what happens when the source shrinks to a point. +- **Truncate a series and quantify what the truncation costs.** Sum a geometric series, approximate it by its leading term, determine how many terms a given accuracy requires, and identify where a Taylor series ceases to converge. +- **Read a gradient off a figure.** Show that $\nabla r = \hat{\boldsymbol{r}}$, that $\nabla f$ is normal to the level surfaces of $f$, and that $dp/dl = \lvert\nabla p\rvert\cos\psi$, so that the magnitude of the gradient is the maximum rate of change. +- **Convert a potential into a field, and a field into a survey.** Apply $\boldsymbol{E} = -\nabla V$ and Ohm's law $\boldsymbol{J} = -\rho^{-1}\nabla V$, and map the potential and current density of a two-electrode DC resistivity measurement. +- **Distinguish diverging arrows from non-zero divergence.** Compute $\nabla\cdot\boldsymbol{v}$, justify the result by flux rather than by algebra, and identify the only radial flow that is incompressible. +- **Use the divergence theorem as a measurement.** Verify $\oint_S\boldsymbol{v}\cdot\hat{\boldsymbol{n}}\,dS = \int_{\mathcal{D}} \nabla\cdot\boldsymbol{v}\,dV$ numerically, and account for what happens when the source shrinks to a point. :::{admonition} Two sessions :class: note -**Session 1** runs to the end of Part 4, covering the gradient. **Part 5 onwards is the following session**, once the divergence has been lectured. Everything is in one page so you can work ahead if you want to. +**Session 1** runs to the end of Part 4 and covers the gradient. **Part 5 onwards belongs to the following session**, after the divergence has been lectured. Both sessions are on one page, so you can read ahead. ::: --- ## Part 0 — Setup -Run this once. Nothing in it is physics: it fetches two packages the browser lacks, finds `fwtools`, and defines the Coulomb constant for later. +Run this once. It contains no physics: it fetches two packages the browser lacks, locates `fwtools`, and defines the Coulomb constant. ```{code-cell} ipython3 -# Nothing above the K = ... line near the bottom is physics; skip to there. +# No physics above the k_e = ... line near the bottom. import sys, pathlib import numpy as np import matplotlib.pyplot as plt from scipy.constants import epsilon_0 -# --- Live Code housekeeping; nothing here is part of the physics ------------ +# --- Live Code housekeeping, not part of the physics ----------------------- try: import plotly.io as pio except ModuleNotFoundError: @@ -96,9 +96,9 @@ print(f"k_e = {k_e:.4e} V*m/C") --- -## Part 1 — Series, and what you lose by truncating +## Part 1 — Series and truncation -Before any fields, one point that runs through the whole course: a physical quantity is often an infinite sum, and we almost always keep only the first few terms. This part is about what that costs. +A physical quantity is often an infinite sum, of which only the first few terms are kept. Two questions follow: what the truncation costs, and whether the sum converges at all. ### Task 1 — the bouncing ball @@ -110,7 +110,7 @@ so it returns to the ground after $T_0 = 2v_0/g$ having reached a height $H = v_ $$ T_n = (1-\gamma)^{n/2}\,T_0, \qquad T_0 = \sqrt{8H/g}. $$ -Fill in the three physical lines. The plotting is written for you. +Fill in the three physical lines; the plotting is given. ```{code-cell} ipython3 g, v0, gamma = 9.81, 5.0, 0.1 @@ -147,15 +147,15 @@ T = T0 * (1 - gamma)**(np.arange(N)/2) ``` ::: -Now the series. The ball bounces for a total time +The ball bounces for a total time $$ T_\infty = \sum_{m=0}^{\infty} T_m = T_0\sum_{m=0}^{\infty}\left(\sqrt{1-\gamma}\right)^{m} = \frac{\sqrt{8H/g}}{1-\sqrt{1-\gamma}}, $$ -which is a geometric series with ratio $\sqrt{1-\gamma}$. That ratio is smaller than 1 for any real bounce, so the sum is **finite** — infinitely many bounces, over in about twenty seconds. (Hold on to the condition: Task 2 is about what happens to a series when it fails.) For small $\gamma$ the expansion $\sqrt{1-\gamma}\approx 1-\gamma/2$ collapses that to something much simpler, +a geometric series with ratio $\sqrt{1-\gamma}$. The ratio is smaller than 1 for any real bounce, so the sum is **finite**: infinitely many bounces, completed in about twenty seconds. The convergence condition matters, and Task 2 examines a series that fails it. For small $\gamma$, the expansion $\sqrt{1-\gamma}\approx 1-\gamma/2$ reduces the sum to $$ T_\infty \approx \sqrt{8H/g}\;\frac{2}{\gamma}. $$ -Two questions follow, and both are worth answering by measurement rather than by intuition: **how good is that approximation**, and **how many bounces must you actually add up** before the running total gets there? +Both questions are answered below by measurement: **how accurate is that approximation**, and **how many bounces must be summed** before the running total reaches $T_\infty$? ```{code-cell} ipython3 rows = {} @@ -172,8 +172,8 @@ for gam in (0.5, 0.2, 0.1, 0.02): f"{abs(T_appr-T_inf)/T_inf:>6.1%} {n99:>10}") # --- self-check (leave this alone) --- -# Your closed form against a brute-force sum of 5000 bounces: the same -# number by two routes, one of which never assumed the series converges. +# The closed form against a brute-force sum of 5000 bounces: one number by +# two routes, one of which never assumed the series converges. _summed = np.sum(T0 * (1 - 0.1)**(np.arange(5000)/2)) fw.check(f"your T_inf at gamma = 0.1 ({rows[0.1][0]:.3f} s) equals the " f"brute-force sum ({_summed:.3f} s)", @@ -195,22 +195,22 @@ fw.check(f"your approximation overshoots by 2.6% there " :::{admonition} What the table says :class: important -At $\gamma = 0.5$ the leading-term approximation is 17% wrong; at $\gamma = 0.02$ it is 0.5%. "Keep only the first term" is not a statement about algebra — it is a statement about the *regime*, and it has to be earned. +At $\gamma = 0.5$ the leading-term approximation is 17% wrong; at $\gamma = 0.02$ it is 0.5%. Keeping only the first term is a claim about the regime, not about the algebra, and it has to be justified case by case. -The term count runs the other way. The more nearly elastic the ball, the more bounces you must sum for the same accuracy: 14 at $\gamma = 0.5$, 456 at $\gamma = 0.02$. Cheap approximation, expensive summation — and the two get cheap and expensive at opposite ends. You will meet that trade in every numerical method this course touches. +The term count runs the other way. The more nearly elastic the ball, the more bounces the same accuracy requires: 14 at $\gamma = 0.5$, 456 at $\gamma = 0.02$. The approximation is cheapest exactly where the summation is most expensive. The same trade-off appears in every numerical method in this course. ::: ### Task 2 — where a Taylor series stops working -A function that is smooth enough — and whose series actually sums back to it, which is the catch this task is about — can be written as a Taylor series about $x=0$, +A function that is smooth enough, and whose series sums back to it, can be written as a Taylor series about $x=0$, -$$ f(x) = f(0) + x f'(0) + \tfrac{1}{2}x^2 f''(0) + \cdots, $$ +$$ f(x) = f(0) + x f'(0) + \tfrac{1}{2}x^2 f''(0) + \cdots . $$ -and in practice we truncate it after a few terms. Take two: +In practice the series is truncated after a few terms. Compare two cases: $$ \sin x = x - \frac{x^3}{3!} + \frac{x^5}{5!} - \cdots, \qquad\qquad \frac{1}{1+x} = 1 - x + x^2 - x^3 + \cdots $$ -Both look equally harmless. Add terms to each and watch what happens. +The two expansions look equally harmless. Add terms to each and compare. ```{code-cell} ipython3 x = np.linspace(-3, 3, 600) @@ -261,18 +261,18 @@ def geo_term(m, x): :::{admonition} Radius of convergence :class: important -$\sin x$ improves everywhere as you add terms. $1/(1+x)$ improves only inside $\lvert x\rvert < 1$; outside it, each extra term makes the partial sum *worse*, without limit — at $x = 1.5$ the 40-term "approximation" is off by millions. +$\sin x$ improves everywhere as terms are added. $1/(1+x)$ improves only inside $\lvert x\rvert < 1$; outside, each extra term makes the partial sum worse without limit, and at $x = 1.5$ the 40-term partial sum is off by millions. -The series has a **radius of convergence** of 1, and no amount of computing power moves it. What sets it is the distance from the point you expanded about to the nearest place the function blows up — here from $x=0$ to the pole at $x=-1$, one unit away. Notice that the failure is invisible at $x = 0$ itself: the function is perfectly smooth there, and the first few terms behave well. Expand the same function about $x = 1$ instead and the radius becomes 2, because the pole is now twice as far off. **The limit is set by where the function misbehaves, not by how well behaved it looks where you started.** +The series has a **radius of convergence** of 1, and no amount of computing power extends it. The radius is the distance from the expansion point to the nearest singularity of the function, here from $x=0$ to the pole at $x=-1$. The failure is invisible at $x = 0$ itself, where the function is smooth and the first few terms behave well. Expanding about $x = 1$ instead gives a radius of 2, because the pole is then twice as far away. **The radius is set by where the function is singular, not by its behaviour at the expansion point.** -Keep that beside Task 1. There, more terms always helped and the only question was how many. Here, more terms are useless past a certain point. Knowing which situation you are in is the whole skill. +Compare Task 1, where more terms always helped and the only question was how many. Here, beyond $\lvert x\rvert = 1$, more terms are useless. Establishing which case applies is a prerequisite to any truncation. ::: --- -## Part 2 — The distance function, and what its gradient is +## Part 2 — The distance function and its gradient -Everything from here on lives on one cube of sample points. +All remaining parts use a single cube of sample points. ```{code-cell} ipython3 n, L = 61, 2.0 # odd n, so the origin is a sample point @@ -281,9 +281,9 @@ X, Y, Z = np.meshgrid(axis, axis, axis, indexing="ij") dx = dy = dz = axis[1] - axis[0] c = n // 2 # index of the origin -# Masks the self-checks reuse. `interior` drops the two outermost cells so -# that comparisons never include the six faces of the box, where a field is -# sampled at its worst and np.gradient has only one-sided neighbours. +# Mask reused by the self-checks. `interior` drops the two outermost cells, +# so comparisons exclude the six faces of the box, where sampling is worst +# and np.gradient has only one-sided neighbours. interior = np.zeros(X.shape, dtype=bool) interior[2:-2, 2:-2, 2:-2] = True @@ -303,34 +303,33 @@ print(f"X[i,j,k] = x[i] -> X[-1, 0, 0] = {X[-1, 0, 0]:.1f} m") | **61** | **0.067** | **0.8%** | **1.6%** | **1.1%** | | 81 | 0.050 | 0.5% | 1.0% | 0.6% | -These are **worst cases** over the region each self-check tests, which is what fixes the tolerances — not an average. Halve $\Delta x$ and the last two columns fall by very nearly the factor of four second order promises (12.5 → 3.3, 9.1 → 2.4). The first column falls by only 2.3, and the reason is worth knowing: the $|\nabla r|$ error grows as you approach the source, so the worst sample in the band $0.4 < r < 1.6$ m is whichever one happens to sit nearest its inner edge — and *that sample moves* when you change `n`. A worst case taken over a boundary the grid keeps redrawing is not a smooth sequence. The clean demonstration is the convergence cell at the end of Part 6, which measures a fixed quantity and does recover the factor of four. +These are **worst cases** over the region each self-check tests, not averages, and they are what fixes the tolerances. Halving $\Delta x$ reduces the last two columns by close to the factor of four that second-order accuracy predicts (12.5 → 3.3, 9.1 → 2.4). The first column falls by only 2.3. The $|\nabla r|$ error grows towards the source, so the worst sample in the band $0.4 < r < 1.6$ m is whichever one sits nearest the inner edge, and that sample moves when `n` changes. A worst case taken over a boundary that the grid keeps redrawing does not form a smooth sequence. The convergence cell at the end of Part 6 measures a fixed quantity instead and does recover the factor of four. -$n = 61$ was chosen by this table: it is the coarsest grid that keeps every task under 2%, and each 3-D figure it produces weighs about 1.5 MB. **If you change `n`, keep it at 41 or above** — the self-checks below allow 5%, and $n = 31$ already fails Task 6 at 6.7%. - -Two more things about this cube. It is a finite window on fields that extend to infinity: the largest closed surface in Part 6 sits only 0.6 m inside the outer face. And $z$ points **up** here, as in any ordinary right-handed frame — Part 4 works on the ground instead, and there $z$ points down into it, as Earth-science convention has it. Neither is more correct; what matters is saying which one you are in. +$n = 61$ was chosen from this table as the coarsest grid that keeps every task under 2%; each 3-D figure it produces is about 1.5 MB. **If you change `n`, keep it at 41 or above.** The self-checks below allow 5%, and $n = 31$ already fails Task 6 at 6.7%. +Two properties of this cube matter later. It is a finite window on fields that extend to infinity: the largest closed surface in Part 6 sits only 0.6 m inside the outer face. And $z$ points **up**, as in an ordinary right-handed frame, whereas Part 4 works in the ground, where $z$ points downwards by Earth-science convention. Neither choice is more correct; stating which one is in use is what matters. The grid is built with `indexing='ij'`, so axis 0 is $x$, axis 1 is $y$, axis 2 is $z$. 1. **Derivatives come back in coordinate order:** `np.gradient(f, dx, dy, dz)` returns $\partial f/\partial x$, $\partial f/\partial y$, $\partial f/\partial z$. No transposes. 2. **Always pass the spacings.** Omit them and the derivative is silently wrong by a factor of $1/\Delta x = 15$. -Numpy's default is `indexing='xy'`, which returns the $y$-derivative first. That one fact is the origin of a large fraction of all numerical field bugs. +NumPy's default is `indexing='xy'`, which returns the $y$-derivative first. That single difference accounts for a large share of numerical field bugs. ::: -Now the geometry. The simplest scalar field there is: +The simplest scalar field is the distance to a point: $$ r(x,y,z) = \sqrt{(x-x_0)^2 + (y-y_0)^2 + (z-z_0)^2} $$ -*How far am I from that point?* One number at every location in space. No charge, no potential, no units of anything — just distance. +One number at every location in space: no charge, no potential, and no units beyond metres. -This is the **spherical** radial coordinate $r$ — distance from a point. The cylindrical $r$, distance from an axis, is a different quantity, and Part 5 returns to the distinction. The equations on this page use $r$; the code calls it `r`, because it is the only radius in the lab. +This is the **spherical** radial coordinate $r$, the distance from a point. The cylindrical radius $\varrho$, the distance from an axis, is a different quantity, and Part 5 returns to the distinction. The equations on this page use $r$, and the code calls it `r`, because it is the only radius in the lab. ### Task 3 — build the distance field -**The question:** what do the surfaces of constant $r$ look like, and where do they crowd together? Answer it in your head first — this is the one field on the page you can picture completely before computing it — then build it and check. +**The question:** what do the surfaces of constant $r$ look like, and where do they crowd together? Answer before computing. This is the one field on the page that can be pictured completely in advance. -The source has to be movable: Task 8 puts two of them down in different places, so write the offsets in now rather than hard-coding the origin. +The source must be movable: Task 8 places two of them at different points, so write the offsets in now rather than hard-coding the origin. ```{code-cell} ipython3 # Task 3 -- distance from a source at (x0, y0, z0) to every point of the grid. @@ -363,7 +362,7 @@ r = distance_to(X, Y, Z) ``` ::: -A surface on which $r$ takes one fixed value is an **isosurface**, or level set — the three-dimensional version of a contour line on a map. Drag the opacity slider under the figure until you can see the inner shells through the outer one. Evenly spaced values of $r$ give evenly spaced shells: the distance function has no favourite radius, which is exactly what makes its gradient so simple in the next task. +A surface on which $r$ takes one fixed value is an **isosurface**, or level set, the three-dimensional analogue of a contour line on a map. Drag the opacity slider under the figure until the inner shells are visible through the outer one. Evenly spaced values of $r$ give evenly spaced shells: the distance function has no preferred radius, which is why its gradient is so simple in the next task. ```{code-cell} ipython3 fw.show_isosurfaces(X, Y, Z, r, levels=[0.5, 1.0, 1.5], label="r [m]", @@ -381,9 +380,9 @@ so, collecting the three components, $$ \nabla r \;=\; \frac{\partial r}{\partial x}\hat{\boldsymbol{x}} + \frac{\partial r}{\partial y}\hat{\boldsymbol{y}} + \frac{\partial r}{\partial z}\hat{\boldsymbol{z}} \;=\; \frac{x\,\hat{\boldsymbol{x}} + y\,\hat{\boldsymbol{y}} + z\,\hat{\boldsymbol{z}}}{r} \;=\; \hat{\boldsymbol{r}} $$ -The last step is the definition of the outward unit radial vector: $\hat{\boldsymbol{r}}$ is exactly the position vector divided by its own length. So $\nabla r$ is a **unit** vector pointing **away** from the source — a direction and a magnitude you now know in advance. +The last step is the definition of the outward unit radial vector: $\hat{\boldsymbol{r}}$ is the position vector divided by its own length. So $\nabla r$ is a **unit** vector pointing **away** from the source, with both direction and magnitude known in advance. -The code below checks whether a finite-difference gradient on a grid reproduces that. Two measurements: the magnitude, which should be 1; and the projection $\nabla r \cdot \hat{\boldsymbol{r}}$, which recovers the full magnitude only if the gradient is *purely* radial, with nothing left over along the sphere. +The cell below tests whether a finite-difference gradient on a grid reproduces that. Two measurements: the magnitude, which should be 1, and the projection $\nabla r \cdot \hat{\boldsymbol{r}}$, which recovers the full magnitude only if the gradient is purely radial, with no component along the sphere. ```{code-cell} ipython3 # The outward unit radial vector, used again later. @@ -394,7 +393,7 @@ rhx, rhy, rhz = X / rs, Y / rs, Z / rs # 1. grad r, as three components. # 2. Its magnitude. # 3. Its projection onto r-hat. -# 4. Draw it, then rotate the figure and compare with the spheres above. +# 4. Draw it, rotate the figure, and compare with the spheres above. grx, gry, grz = ___ # all three spacings, in order @@ -410,10 +409,10 @@ band = (r > 0.4) & (r < 1.6) fw.check_shape("grad r (x-component)", grx, X.shape) fw.check_close("|grad r| = 1 everywhere", grad_r_mag, 1.0, rtol=0.05, where=band) fw.check_close("grad r is purely radial", radial_part, 1.0, rtol=0.05, where=band) -# The two checks above are the same measurement for THIS field, so they can -# only pass or fail together. This one is independent: it compares the three -# components against r-hat one at a time, so a gradient that had the right -# length but the wrong direction would be caught. +# The two checks above are the same measurement for THIS field, so they pass +# or fail together. This one is independent: it compares the three components +# against r-hat separately, catching a gradient of the right length but the +# wrong direction. fw.check(f"grad r = r-hat, componentwise (worst " f"{np.nanmax(np.abs(np.stack([grx-rhx, gry-rhy, grz-rhz]))[:, band]):.3f} " f"of a unit vector)", @@ -436,26 +435,26 @@ print(f"|grad r| median in 0.4 < r < 1.6 m : " :::{admonition} What the algebra means :class: important -$\lvert\nabla r\rvert = 1$ needs no calculus to see: walk one metre directly away from the source and your distance from it grows by exactly one metre, so the steepest rate of change of $r$ is 1 m/m wherever you stand. A gradient carries the direction of steepest increase and a length equal to that rate — here, "away" and 1. +$\lvert\nabla r\rvert = 1$ needs no calculus: move one metre directly away from the source and the distance to it grows by one metre, so the steepest rate of change of $r$ is 1 m/m everywhere. A gradient carries the direction of steepest increase and a length equal to that rate, here outward and 1. -The radial check fixes the other half: moving *along* a sphere does not change $r$, so the gradient has no component there. **$\nabla f$ is normal to the level surfaces of $f$** — for every scalar field, not just this one. +The radial check fixes the other half: moving along a sphere does not change $r$, so the gradient has no component there. **$\nabla f$ is normal to the level surfaces of $f$** for every scalar field, not only this one. -The same chain rule settles the next two tasks in advance: $\nabla g(r) = \dfrac{dg}{dr}\,\hat{\boldsymbol{r}}$ for any $g$ depending on position only through $r$. Derive before you run. +The same chain rule settles the next two tasks in advance: $\nabla g(r) = \dfrac{dg}{dr}\,\hat{\boldsymbol{r}}$ for any $g$ depending on position only through $r$. Derive it before running the cells. ::: -### Task 5 — how fast does it change *that* way? +### Task 5 — the rate of change in an arbitrary direction -The gradient's *direction* is settled: steepest increase, normal to the level surface. Its *magnitude* is the claim we have not tested. It follows from +The direction of the gradient is settled: steepest increase, normal to the level surface. Its magnitude is the untested claim. It follows from $$ dp = (\nabla p)\cdot d\boldsymbol{l} = \lvert\nabla p\rvert\,\lvert d\boldsymbol{l}\rvert\cos\psi \qquad\Longrightarrow\qquad \frac{dp}{dl} = \lvert\nabla p\rvert\cos\psi, $$ -where $d\boldsymbol{l}$ is a small step in whatever direction you choose, $dl = \lvert d\boldsymbol{l}\rvert$ is its length, and $\psi$ is the angle between that step and the gradient. (The step is written $d\boldsymbol{l}$ rather than $d\boldsymbol{r}$ only because $r$ already means the distance from the origin on this page.) +where $d\boldsymbol{l}$ is a small step in any chosen direction, $dl = \lvert d\boldsymbol{l}\rvert$ is its length, and $\psi$ is the angle between the step and the gradient. The step is written $d\boldsymbol{l}$ rather than $d\boldsymbol{r}$ because $r$ already denotes the distance from the origin on this page. -Two things follow, and both are testable: the rate of change in *any* direction is $\lvert\nabla p\rvert\cos\psi$, and it can never exceed $\lvert\nabla p\rvert$ — reached only at $\psi = 0$. +Two testable consequences: the rate of change in any direction is $\lvert\nabla p\rvert\cos\psi$, and it never exceeds $\lvert\nabla p\rvert$, which is reached only at $\psi = 0$. -Measure it. Pick one point, walk a short distance $\varepsilon$ along many different unit vectors $\hat{\boldsymbol{u}}$, and compare the measured rate against the prediction. +Measure it. At one point, step a short distance $\varepsilon$ along many unit vectors $\hat{\boldsymbol{u}}$ and compare each measured rate with the prediction. ```{code-cell} ipython3 p_field = 1.0 / np.maximum(r, 0.25) # any scalar field will do @@ -511,33 +510,33 @@ grad_mag = float(np.linalg.norm(gvec)) ``` ::: -:::{admonition} The magnitude, earned +:::{admonition} The magnitude, measured :class: important -Every measured rate lies on the line. Three readings of the same picture: +Every measured rate lies on the line. Three readings of the same figure: -- **At $\cos\psi = 1$** you are walking straight up the gradient, and the rate equals $\lvert\nabla p\rvert$ exactly. Nothing beats it — that is what "steepest" means, now measured rather than asserted. -- **At $\cos\psi = 0$** you are moving along the level surface and $p$ does not change at all. This is the normality result of Task 4, arriving a second time by a different route. -- **At $\cos\psi = -1$** you get $-\lvert\nabla p\rvert$: the steepest *descent*, which is the direction $\boldsymbol{E} = -\nabla V$ will pick out in Part 3. +- **At $\cos\psi = 1$** the step is straight up the gradient and the rate equals $\lvert\nabla p\rvert$. No direction exceeds it, which is the content of *steepest*, now measured rather than asserted. +- **At $\cos\psi = 0$** the step lies in the level surface and $p$ does not change. This is the normality result of Task 4, recovered by a second route. +- **At $\cos\psi = -1$** the rate is $-\lvert\nabla p\rvert$, the steepest descent, which is the direction $\boldsymbol{E} = -\nabla V$ selects in Part 3. -One vector carries a direction *and* a rate, and the cosine tells you what you get for walking at an angle to it. +One vector carries both a direction and a rate; the cosine gives the rate along any other direction. ::: --- -## Part 3 — Invert it, and watch the arrows turn round +## Part 3 — The inverse distance -Now the function the physics actually uses: not the distance, but **one over** the distance, +The function that appears in the physics is not the distance but its reciprocal, $$ f(r) = \frac{1}{r}, \qquad\text{so}\qquad \nabla f = \frac{d}{dr}\!\left(\frac{1}{r}\right)\hat{\boldsymbol{r}} = -\frac{1}{r^{2}}\,\hat{\boldsymbol{r}} $$ -Same spheres as isosurfaces — $f$ is constant wherever $r$ is constant. But the *ordering* has been turned inside out: $f$ is now largest near the source and decays to nothing far away. Predict what that does to the arrows, then check the prediction against the formula above, then measure it. +The isosurfaces are the same spheres, since $f$ is constant wherever $r$ is constant, but the ordering is inverted: $f$ is largest near the source and decays to zero far away. Predict the effect on the arrows, check the prediction against the formula above, then measure it. ### Task 6 — the gradient of the inverse distance ```{code-cell} ipython3 -# The mask keeps the singularity at r = 0 off the grid. Everything within -# 0.25 m of the source becomes NaN and is simply not measured. +# The mask keeps the singularity at r = 0 off the grid: everything within +# 0.25 m of the source becomes NaN and is not measured. r_masked = np.where(r < 0.25, np.nan, r) f = 1.0 / r_masked @@ -550,8 +549,8 @@ for rr in (0.6, 1.0, 1.5): i = int(np.argmin(np.abs(X[:, 0, 0] - rr))) print(f"r = {rr:.1f} m : |grad f| = {f_mag[i, c, c]:8.4f} 1/r^2 = {1/rr**2:8.4f}") -# normalise=True draws every arrow the same length, so the picture carries -# direction only; the magnitude moves into the colour, on a log scale, +# normalise=True draws every arrow the same length, so the figure carries +# direction only. The magnitude moves into the colour, on a log scale, # because the drawn arrows span a factor of 62. fw.show_cones(X, Y, Z, fx, fy, fz, step=8, normalise=True, label="|∇(1/r)|", unit="m-2", @@ -572,21 +571,21 @@ f_mag = np.sqrt(fx**2 + fy**2 + fz**2) ``` ::: -:::{admonition} The gradient points towards *increase* — always +:::{admonition} The gradient always points towards increase :class: important The arrows have reversed. Same spheres, same source, opposite direction: $$ \nabla r = +\hat{\boldsymbol{r}}, \qquad\qquad \nabla\!\left(\frac{1}{r}\right) = -\frac{1}{r^{2}}\,\hat{\boldsymbol{r}} $$ -Nothing about space changed. What changed is **which way the function climbs**. And the steepness changed too: $1/r$ climbs ever faster as you approach the source, so its gradient grows as $1/r^2$ rather than staying at 1. +Nothing about space changed; what changed is **which way the function climbs**. The steepness changed as well: $1/r$ climbs faster as the source is approached, so its gradient grows as $1/r^2$ instead of staying at 1. -A gradient knows nothing about sources, sinks, charges or fields. It only knows uphill. +A gradient encodes nothing about sources, sinks, charges or fields. It encodes only the uphill direction and the rate along it. ::: ### Task 7 — from geometry to physics -Here the physics enters, and it enters as a single minus sign. The electric potential of a point charge $Q$ is the inverse-distance function with a constant in front, +The physics enters as a single minus sign. The electric potential of a point charge $Q$ is the inverse-distance function with a constant in front, $$ V(r) = \frac{1}{4\pi\varepsilon_0}\frac{Q}{r}\quad[\text{V}], $$ @@ -594,7 +593,7 @@ and the electric field is *defined* as $$ \boldsymbol{E} = -\nabla V \quad[\text{V/m}]. $$ -You already know what $\nabla V$ does: it points inward, uphill towards the charge. The minus sign turns it round, so **the field points downhill** — which is exactly the way a positive test charge released from rest would move, losing potential energy as it goes. +$\nabla V$ points inward, uphill towards the charge. The minus sign reverses it, so **the field points downhill**, which is the direction a positive test charge released from rest would move, losing potential energy as it goes. ```{code-cell} ipython3 V = k_e * Q / r_masked @@ -629,34 +628,34 @@ E_mag = np.sqrt(Ex**2 + Ey**2 + Ez**2) ``` ::: -:::{admonition} Why bother with $V$ at all? +:::{admonition} Why the potential is worth defining :class: tip -$V$ is a scalar: one number per point, no direction to keep track of. $\boldsymbol{E}$ is a vector: three. Anything you can do once on $V$ and then differentiate is cheaper — in arithmetic and in bookkeeping — than doing it three times on $\boldsymbol{E}$. +$V$ is a scalar: one number per point, with no direction to track. $\boldsymbol{E}$ is a vector: three numbers. Any operation carried out once on $V$ and then differentiated is cheaper, in arithmetic and in bookkeeping, than the same operation carried out three times on $\boldsymbol{E}$. -Part 4 is the first payoff, and it is the reason the potential is worth defining in the first place. +Part 4 is the first case where this matters. ::: --- ## Part 4 — Two sources: superposition -One charge is symmetric enough to be boring. Put down two: +A single charge is spherically symmetric. Two are not: $$ V_{\text{total}} = \frac{1}{4\pi\varepsilon_0}\left(\frac{Q_1}{r_1} + \frac{Q_2}{r_2}\right) $$ -**Superposition** for the potential is nothing more than adding two numbers at every point, because $V$ is a scalar. Adding the two *fields* instead would mean a vector sum at every point in the cube. +**Superposition** of potentials is the addition of two numbers at every point, because $V$ is a scalar. Superposing the two fields instead requires a vector sum at every point of the cube. -Since $\nabla$ is a linear operator, $-\nabla(V_1 + V_2) = \boldsymbol{E}_1 + \boldsymbol{E}_2$ exactly. So the efficient route is: **add the potentials, then take one gradient at the very end.** Nothing is lost. +Since $\nabla$ is linear, $-\nabla(V_1 + V_2) = \boldsymbol{E}_1 + \boldsymbol{E}_2$ exactly. The efficient route is therefore to **add the potentials and take a single gradient at the end**, with no loss of accuracy. ### Task 8 — build a dipole ```{code-cell} ipython3 -# Distances to the two charges. +Q sits at x = +d/2, -Q at x = -d/2 -- the -# same placement Task 9 will give the current source and sink, so the two -# pictures can be laid side by side. The guard only trips if a grid point -# lands exactly on a charge; at n = 61 none does, so nothing is masked here -# and you see the full field. Raise it if you change the grid. +# Distances to the two charges. +Q sits at x = +d/2, -Q at x = -d/2, the same +# placement Task 9 gives the current source and sink, so the two figures can +# be compared directly. The guard trips only if a grid point lands exactly on +# a charge; at n = 61 none does, so nothing is masked and the full field is +# shown. Raise it if you change the grid. d_sep = 1.0 # charge separation [m] r_plus = np.where(distance_to(X, Y, Z, +d_sep/2, 0.0, 0.0) < 0.01, np.nan, distance_to(X, Y, Z, +d_sep/2, 0.0, 0.0)) @@ -692,23 +691,23 @@ Ex_d, Ey_d, Ez_d = -dVx, -dVy, -dVz ``` ::: -:::{admonition} Look at the mid-plane before you move on +:::{admonition} The mid-plane :class: tip -At $x = 0$, the potential is **exactly zero**. Yet the field there is not zero at all: it is at its strongest, pointing straight from the positive charge to the negative one — here in the $-\hat{\boldsymbol{x}}$ direction, since $+Q$ sits on the right. +At $x = 0$ the potential is **exactly zero**, while the field is at its strongest, pointing straight from the positive charge to the negative one, here along $-\hat{\boldsymbol{x}}$ because $+Q$ sits on the right. -The field is the *slope* of the potential, not its value. A landscape can be at sea level and still be steep. Notice also what the picture shows about direction: the streamlines cross the coloured contours at right angles everywhere, which is Task 4's normality result showing up in a field you did not construct radially. +The field is the slope of the potential, not its value: terrain at sea level can still be steep. The figure also shows the streamlines crossing the coloured contours at right angles everywhere, which is the normality result of Task 4 appearing in a field that was not constructed radially. ::: -### Far away, it is one object +### The far field of the dipole -Now the connection back to Part 1. Nothing about $V_{\text{dip}}$ is a series — it is two exact terms. But step far enough back and the two charges stop being resolvable, and what survives is a **truncation**. +$V_{\text{dip}}$ is not a series; it is two exact terms. Viewed from far enough away, however, the two charges are no longer resolvable, and what survives is a **truncation**. -Expand $1/r_\pm$ in powers of $d/r$ and add. The two leading terms are equal and opposite — the charges cancel, as they must, since the pair carries no net charge — and the first thing left is +Expand $1/r_\pm$ in powers of $d/r$ and add. The leading terms are equal and opposite, since the pair carries no net charge, and the first surviving term is $$ V \;\approx\; \frac{1}{4\pi\varepsilon_0}\frac{\boldsymbol{p}\cdot\hat{\boldsymbol{r}}}{r^{2}}, \qquad \boldsymbol{p} = Q d\,\hat{\boldsymbol{x}}, $$ -the **dipole moment** $\boldsymbol{p}$ pointing from the negative charge to the positive one. Everything dropped is smaller by a further factor of $(d/r)^2$ — so this is Task 1's question again, asked of space instead of time: *how far away do you have to stand before one term is enough?* +with the **dipole moment** $\boldsymbol{p}$ pointing from the negative charge to the positive one. Every discarded term is smaller by a further factor of $(d/r)^2$. This is the question of Task 1 asked of distance rather than of term count: at what range is one term enough? ```{code-cell} ipython3 # --- given: exact against the one-term far field, along the +x axis --- @@ -738,14 +737,14 @@ fw.check("the far-field error falls as (d/r)^2", :::{admonition} The same question as the bouncing ball :class: important -Two decades of accuracy cost about a factor of ten in distance: good to 10% at $1.6\,d$, to 1% at $5\,d$, to 0.1% at $16\,d$. That is the $(d/r)^2$ law, and $\sqrt{10} \approx 3.2$ is the factor between each pair. +Two decades of accuracy cost a factor of ten in distance: 10% at $1.6\,d$, 1% at $5\,d$, 0.1% at $16\,d$. This is the $(d/r)^2$ law, and the factor between successive rows is $\sqrt{10}\approx 3.2$. -Compare it with Task 1. There, "how many terms for 1%?" had the answer 88, and it grew as the ball became more elastic. Here the knob is not a term count but a *distance*, and the answer grows the closer you stand. In both cases the truncation is only as good as the regime, and in both cases you can find out which regime you are in by measuring rather than hoping. +Compare Task 1, where 1% accuracy required 88 terms, and the count grew as the ball became more elastic. Here the controlling variable is a distance rather than a term count, and the requirement grows the closer the observation point. In both cases the truncation is only as good as the regime, and in both cases the regime can be established by measurement. -This one term is why a compass works. A magnet has a complicated field close up; a metre away it is a dipole and nothing else, which is exactly why the Earth's field is worth writing as the single term you will meet in Task 11. +This single term is why a compass works. A magnet has a complicated field close up; at a metre it is a dipole and nothing else, which is why the Earth's field is written as the single term used in Task 11. ::: -The same object in three dimensions — positive and negative equipotential surfaces together, drawn transparent: +The same object in three dimensions, with positive and negative equipotential surfaces drawn transparent: ```{code-cell} ipython3 lobe = np.nanpercentile(np.abs(V_dip), 97) @@ -754,11 +753,11 @@ fw.show_isosurfaces(X, Y, Z, np.nan_to_num(V_dip), levels=[-lobe, -lobe/3, lobe/ title="Equipotential surfaces of a dipole") ``` -### Task 9 — the same mathematics, as a geophysical survey +### Task 9 — the same mathematics as a geophysical survey -Everything you just built was two charges in vacuum. Now change nothing about the mathematics and everything about the physics. +Task 8 was two charges in vacuum. The mathematics below is identical; the physics is not. -Drive a current $I$ into the ground through one electrode and take it out through another, a distance $a$ apart. In ground of resistivity $\rho$ the current spreads through the **lower half-space only** — air does not conduct — so each electrode contributes $\rho I/2\pi r$ rather than $\rho I / 4\pi r$, and superposition gives +Drive a current $I$ into the ground through one electrode and extract it through another, a distance $a$ away. Air does not conduct, so in ground of resistivity $\rho$ the current spreads through the **lower half-space only**, and each electrode contributes $\rho I/2\pi r$ rather than $\rho I / 4\pi r$. Superposition gives $$ V(x,y,z) = \frac{\rho I}{2\pi}\left(\frac{1}{\lvert\boldsymbol{r}-\boldsymbol{a}/2\rvert} - \frac{1}{\lvert\boldsymbol{r}+\boldsymbol{a}/2\rvert}\right), \qquad z \ge 0 \ \text{(down into the ground)}. $$ @@ -766,17 +765,17 @@ The field follows as before, $\boldsymbol{E} = -\nabla V$, and Ohm's law in loca $$ \boldsymbol{J} = \rho^{-1}\boldsymbol{E} = -\rho^{-1}\nabla V \quad [\text{A}/\text{m}^2]. $$ -This is a real measurement — a DC resistivity survey, the workhorse of near-surface geophysics. Map it two ways: on the ground surface, where the electrodes are planted, and on a vertical section cut down between them. +This is a DC resistivity survey, a standard near-surface geophysical measurement. Map it two ways: on the ground surface, where the electrodes are planted, and on a vertical section cut between them. -:::{admonition} Careful — $\rho$ means something else here +:::{admonition} $\rho$ means something else here :class: warning -In this task $\rho$ is the **electrical resistivity** in Ω·m. In Task 13 it will be a charge density in C/m³, written $\rho_v$ to keep them apart. The symbol is overloaded across the whole subject; the units tell you which is which. +In this task $\rho$ is the **electrical resistivity** in Ω·m. In Task 13 it is a charge density in C/m³, written $\rho_v$ to keep the two apart. The symbol is overloaded throughout the subject; the units identify which is meant. ::: -The ground is a half-space, so this needs its own grid: $x$ and $y$ still run $-L$ to $L$, but $z$ runs from $0$ (the surface) **downwards**, the Earth-science convention. +The ground is a half-space, so this task needs its own grid: $x$ and $y$ still run from $-L$ to $L$, but $z$ runs from $0$ at the surface **downwards**, following the Earth-science convention. -A real electrode is a metal stake, not a mathematical point: a conductor of some finite radius $r_{\text{el}}$, held at one potential over its whole surface. Model it that way — floor the distance at $r_{\text{el}}$ — and $1/r$ never blows up. Nothing is masked, no sample is thrown away, and every derivative below is taken on a field that is finite everywhere. +A real electrode is a metal stake, not a mathematical point: a conductor of finite radius $r_{\text{el}}$ held at one potential over its whole surface. Flooring the distance at $r_{\text{el}}$ models it that way and keeps $1/r$ bounded. Nothing is masked, no sample is discarded, and every derivative below acts on a field that is finite everywhere. ```{code-cell} ipython3 rho, I, a_sep = 100.0, 1.0, 1.0 # ohm.m, ampere, electrode spacing [m] @@ -797,9 +796,9 @@ def dist_to(x0): # V: the formula above, source at x = +a_sep/2, sink at x = -a_sep/2. # dist_to floors the distance at the electrode radius, so there is # nothing to mask and nothing to nan_to_num. -# J: -grad(V)/rho. Pass dxg, dxg, dzg. On this grid z really is spaced +# J: -grad(V)/rho. Pass dxg, dxg, dzg. On this grid z is spaced # differently from x and y, and passing dxg three times costs 6.5% on -# the current measured in the next cell -- enough to fail its check. +# the current measured in the next cell, enough to fail its check. V_dc = ___ Jx, Jy, Jz = ___ @@ -838,10 +837,10 @@ gVx, gVy, gVz = np.gradient(V_dc, dxg, dxg, dzg) Jx, Jy, Jz = -gVx/rho, -gVy/rho, -gVz/rho ``` -One presentation point worth stealing for your own figures: `show_field_slice` returns `(ax, cf)`, so passing `colorbar=False` on both panels and handing the mappable `cf` to `fig.colorbar(..., ax=axes)` draws **one** bar beside the pair. Two bars carrying identical numbers is clutter, and it invites the reader to think the scales differ. +A presentation point worth reusing: `show_field_slice` returns `(ax, cf)`, so passing `colorbar=False` on both panels and handing the mappable `cf` to `fig.colorbar(..., ax=axes)` draws **one** bar beside the pair. Two bars carrying identical numbers are clutter, and they suggest to the reader that the scales differ. ::: -Now use the field as an instrument. *All* the current injected at one electrode has to cross any closed surface you draw around it — there is nowhere else for it to go. Test that. +Now use the field as an instrument. All the current injected at one electrode must cross any closed surface drawn around it, since there is nowhere else for it to go. Test that. ```{code-cell} ipython3 # The five faces of a box buried in the ground around one electrode. The top @@ -870,11 +869,11 @@ fw.check_scalar("box around the sink carries -I", buried_box_current(-a_sep/2), :::{admonition} Why five faces and not six? :class: important -The box is closed by the ground surface itself. Air does not conduct, so $J_z = 0$ at $z=0$ — a **boundary condition**, true by physics, not something to be measured. +The box is closed by the ground surface itself. Air does not conduct, so $J_z = 0$ at $z=0$. This is a **boundary condition**, true by physics, and not a quantity to be measured. -It is worth seeing what happens if you do try to measure it. `np.gradient` has no neighbour above $z=0$, so it falls back to a one-sided difference there — and reports a spurious $J_z$ averaging $+0.25$ A/m² over the top of the box, current apparently sinking in from the air. The outward normal on that face is $-\hat{\boldsymbol{z}}$, so it enters the sum as $-0.088$ A and drags the box from $1.003$ A down to $0.915$ A: an **8.5% error**, on a result that is otherwise good to 0.3%. +Measuring it anyway is instructive. `np.gradient` has no neighbour above $z=0$, so it falls back to a one-sided difference and reports a spurious $J_z$ averaging $+0.25$ A/m² over the top of the box, apparently current entering from the air. The outward normal on that face is $-\hat{\boldsymbol{z}}$, so the face enters the sum as $-0.088$ A and reduces the box total from $1.003$ A to $0.915$ A, an **8.5% error** on a result that is otherwise accurate to 0.3%. -The lesson generalises well beyond this lab: **where you know a boundary condition exactly, impose it — do not ask a finite-difference stencil to rediscover it.** Numerical derivatives are least trustworthy exactly where your domain stops. +The rule generalises well beyond this lab: **impose a boundary condition you know exactly, rather than asking a finite-difference stencil to recover it.** Numerical derivatives are least reliable where the domain stops. ::: --- @@ -882,30 +881,30 @@ The lesson generalises well beyond this lab: **where you know a boundary conditi :::{admonition} End of session 1 :class: note -Parts 1–4 are the gradient, and that is where the first afternoon ends. **Part 5 onwards needs the divergence**, which is lectured next — come back to it in the following session, or read ahead if you are curious. +Parts 1–4 cover the gradient and close the first session. **Part 5 onwards requires the divergence**, which is lectured next. Return to it in the following session, or read ahead. ::: --- -## Part 5 — Divergence: is anything being created here? +## Part 5 — Divergence -The gradient took a scalar and returned a vector. The divergence goes the other way — hand it a vector field, get back a scalar: +The gradient takes a scalar and returns a vector. The divergence takes a vector field and returns a scalar: $$ \nabla\cdot\boldsymbol{A} \;=\; \lim_{\Delta V \to 0}\frac{1}{\Delta V}\oint_S \boldsymbol{A}\cdot\hat{\boldsymbol{n}}\,dS \;=\; \frac{\partial A_x}{\partial x} + \frac{\partial A_y}{\partial y} + \frac{\partial A_z}{\partial z} $$ -Read the definition on the left, not the formula on the right: **treat $\boldsymbol{A}$ as the velocity of a fluid**, put a small box anywhere, and measure the net outflow through its walls per unit volume. +Read the definition on the left rather than the formula on the right: **treat $\boldsymbol{A}$ as a fluid velocity**, place a small box anywhere, and measure the net outflow through its walls per unit volume. | $\nabla\cdot\boldsymbol{A}$ | Name | Picture | | :---: | :--- | :--- | -| $> 0$ | **source** | a tap — more leaves than arrives | -| $< 0$ | **sink** | a drain — more arrives than leaves | +| $> 0$ | **source** | a tap: more leaves than arrives | +| $< 0$ | **sink** | a drain: more arrives than leaves | | $= 0$ | **solenoidal** | whatever flows in, flows out | -### Task 10 — the operator, and where it is measured from +### Task 10 — the operator, and its independence of the origin -The operator itself is three lines, and you are given them. One derivative along one axis per component: `np.gradient(Ax, dx, axis=0)` returns $\partial A_x/\partial x$ and nothing else, where asking for all three and discarding two would cost three times the memory. The cross terms are not part of a divergence. +The operator is three lines, and they are given. One derivative along one axis per component: `np.gradient(Ax, dx, axis=0)` returns $\partial A_x/\partial x$ and nothing else, whereas asking for all three and discarding two costs three times the memory. The cross terms are not part of a divergence. -**The question is the one the definition raises.** Flux per unit volume is measured around *a point* — so does the answer depend on which point you call the origin? Take the outward flow $\boldsymbol{A} = \boldsymbol{r}$, whose divergence you can do on paper: $1+1+1 = 3$. Now shift the whole field so it streams out of $(0.8, -0.4, 0.3)$ instead. Predict the divergence before you compute it. +**The question is the one raised by the definition.** Flux per unit volume is measured around a point, so does the result depend on which point is called the origin? Take the outward flow $\boldsymbol{A} = \boldsymbol{r}$, whose divergence follows on paper as $1+1+1 = 3$, then shift the whole field so that it streams out of $(0.8, -0.4, 0.3)$. Predict the divergence before computing it. ```{code-cell} ipython3 # --- given --- @@ -937,17 +936,17 @@ div_shifted = divergence(Sx, Sy, Sz, dx, dy, dz) ``` ::: -:::{admonition} Why it had to be 3 either way +:::{admonition} Why the answer had to be 3 either way :class: tip -Moving the source changed every arrow in the box, and changed the divergence nowhere. Differentiation kills the constant: $\partial(x - x_0)/\partial x = 1$ whatever $x_0$ is. +Moving the source changed every arrow in the box and changed the divergence nowhere. Differentiation removes the constant: $\partial(x - x_0)/\partial x = 1$ for any $x_0$. -That is worth more than it looks. The divergence is a **local** quantity — it is built from a limit taken around one point, so it can only know about the field in a shrinking neighbourhood of that point, and nothing about where you chose to put your axes. Every operator in this course has that property, and it is what lets you write $\nabla\cdot\boldsymbol{E} = \rho_v/\varepsilon_0$ as a statement about *places* rather than about coordinate systems. +The divergence is a **local** quantity: it is built from a limit taken around one point, so it depends on the field in a shrinking neighbourhood of that point and not on where the axes were placed. Every operator in this course has that property, and it is what makes $\nabla\cdot\boldsymbol{E} = \rho_v/\varepsilon_0$ a statement about places rather than about coordinate systems. ::: ### Task 11 — the only incompressible radial flow -A first use of the operator. Water of constant density flows outward from a source at the origin. Away from that source nothing is created or destroyed, so the flow must be **incompressible**: +Water of constant density flows outward from a source at the origin. Away from that source nothing is created or destroyed, so the flow is **incompressible**: $$ \nabla\cdot\boldsymbol{v} = 0 \qquad \text{for } r \neq 0. $$ @@ -955,15 +954,15 @@ Constant density and a point source force the flow to be radial, $\boldsymbol{v} $$ \nabla\cdot\boldsymbol{v} = 3f(r) + r\frac{df}{dr} = 0 \qquad\Longrightarrow\qquad f(r) = \frac{A}{r^{3}}. $$ -Do not take that on trust — find it. Try four candidates and let the divergence pick. +Rather than assume this, test four candidates and let the divergence select. ```{code-cell} ipython3 -# The measure to report, once, so the loop below reads as physics: +# The measure reported by the loop below: # # |div v| / (|v| / r), median over the test band # # |v|/r is the natural size of a derivative of v, so the ratio is a pure -# number -- 1 means "as large as a derivative of this field could be". +# number: 1 means "as large as a derivative of this field could be". r_safe = np.where(r < 0.3, np.nan, r) band_i = interior & (r > 0.6) & (r < 1.6) @@ -1010,28 +1009,28 @@ fw.check(f"f = const reproduces Task 10's div(r) = 3 ({results['const']:.2%})", :::{admonition} Where the inverse-square law comes from :class: important -One candidate sits at 300%, two at almost exactly 100%, and one at 0.66%. Only $f = A/r^{3}$ survives, exactly as the algebra says. +One candidate gives 300%, two give almost exactly 100%, and one gives 0.66%. Only $f = A/r^{3}$ survives, as the algebra predicts. -The 300% is not an accident, and it is worth recognising: for $f = \text{const}$ the field *is* the position vector, $\boldsymbol{v} = \boldsymbol{r}$, whose divergence you measured in Task 10 as exactly 3 — while $\lvert\boldsymbol{v}\rvert/r = 1$, so the ratio has to be 3. Note also what the surviving case means for the field itself: +The 300% is not an accident. For $f = \text{const}$ the field is the position vector, $\boldsymbol{v} = \boldsymbol{r}$, whose divergence Task 10 measured as exactly 3, while $\lvert\boldsymbol{v}\rvert/r = 1$, so the ratio must be 3. The surviving case rewrites as $$ \boldsymbol{v} = \frac{A}{r^{3}}\boldsymbol{r} = \frac{A}{r^{2}}\,\hat{\boldsymbol{r}}. $$ -**That is the same $1/r^{2}$ you have been working with since Task 6.** Here it was not assumed, and no charge was mentioned: it fell out of "nothing is created away from the source" plus "space is three-dimensional". The surface of a sphere grows as $r^{2}$, so a fixed amount of stuff crossing it must thin as $1/r^{2}$. +**This is the same $1/r^{2}$ used since Task 6.** Here it was not assumed and no charge was mentioned; it follows from conservation away from the source together with the three-dimensionality of space. The surface of a sphere grows as $r^{2}$, so a fixed flux crossing it must thin as $1/r^{2}$. -Coulomb's law, Newton's gravity and this water all share an exponent for that one geometric reason. +Coulomb's law, Newtonian gravity and this flow share an exponent for that one geometric reason. ::: ### Task 11, continued — a field with no source anywhere -Notice the small print on that result: $\nabla\cdot\boldsymbol{v} = 0$ **for $r \neq 0$**. The origin is excluded, and it has to be — that is where the water is injected. Put a closed surface around it and you would find the tap. +Note the restriction on that result: $\nabla\cdot\boldsymbol{v} = 0$ **for $r \neq 0$**. The origin must be excluded, because that is where the water is injected; a closed surface around it would find the tap. -Now a field with no such exception. To first order the Earth's magnetic field is a **dipole**: a north and a south pole so close together that they coincide. With dipole moment $\boldsymbol{m}$, +The next field admits no such exception. To first order the Earth's magnetic field is a **dipole**: a north and a south pole so close together that they coincide. With dipole moment $\boldsymbol{m}$, $$ \boldsymbol{B} = \frac{3\boldsymbol{r}\,(\boldsymbol{r}\cdot\boldsymbol{m}) - r^{2}\boldsymbol{m}}{r^{5}}. $$ Take $\boldsymbol{m} = \hat{\boldsymbol{z}}$ on the cube of Part 2, where $z$ points up, and measure the divergence with the same function. -(The Earth's own moment points roughly geographic *south*, which is why the magnetic pole in the Arctic is magnetically a **south** pole and pulls the north end of a compass needle towards it. Reversing $\boldsymbol{m}$ reverses every arrow below and changes nothing at all about $\nabla\cdot\boldsymbol{B}$, which is the point of the task.) +The Earth's own moment points roughly geographic south, which is why the magnetic pole in the Arctic is magnetically a **south** pole and attracts the north end of a compass needle. Reversing $\boldsymbol{m}$ reverses every arrow below and leaves $\nabla\cdot\boldsymbol{B}$ unchanged. ```{code-cell} ipython3 # Task 11, continued -- fill in the three components. @@ -1070,28 +1069,28 @@ Bz = (3*Z*r_dot_m - r_safe**2) / r_safe**5 :::{admonition} No magnetic monopoles :class: important -Both fields are divergence-free where you measured, but they are not the same statement. +Both fields are divergence-free over the region measured, but the two statements differ. -The water needed an exclusion: $\nabla\cdot\boldsymbol{v} = 0$ *away from the origin*, because the origin is a tap. The dipole needs none — $\nabla\cdot\boldsymbol{B} = 0$ holds **everywhere in space, including at the source itself**. There is no point you could exclude and find a magnet leaking field the way the tap leaks water. That is one of Maxwell's equations, and it says magnetic monopoles do not exist: field lines of $\boldsymbol{B}$ never begin and never end, they only close on themselves. +The flow required an exclusion: $\nabla\cdot\boldsymbol{v} = 0$ away from the origin, because the origin is a tap. The dipole requires none, and $\nabla\cdot\boldsymbol{B} = 0$ holds **everywhere in space, including at the source**. No point can be excluded to reveal a magnet leaking field the way the tap leaks water. This is one of Maxwell's equations: magnetic monopoles do not exist, and field lines of $\boldsymbol{B}$ never begin or end but close on themselves. -Two footnotes on the numbers. Both cells report the same scale-free measure, so the numbers are directly comparable: the dipole's 1.8% is worse than the radial flow's 0.66% — not because the physics is shakier but because $\boldsymbol{B}$ falls off as $1/r^{3}$ instead of $1/r^{2}$, so a centred difference has more curvature to miss. Part 6 pushes the "no exception" claim far below that 2%, by putting a closed surface around the dipole instead of differentiating it. +Two remarks on the numbers. Both cells report the same scale-free measure, so the results are directly comparable. The dipole's 1.8% is worse than the radial flow's 0.66%, not because the physics is less secure but because $\boldsymbol{B}$ falls off as $1/r^{3}$ rather than $1/r^{2}$, leaving a centred difference more curvature to miss. Part 6 tests the same claim far below 2% by putting a closed surface around the dipole instead of differentiating it. -And the second check is worth a moment: $\boldsymbol{B}\cdot\boldsymbol{r}$ goes negative somewhere, which the outward flow of Task 11 never does. The dipole points *inward* over part of space — it returns. That is what "closes on itself" looks like in a number. +The second check is also informative: $\boldsymbol{B}\cdot\boldsymbol{r}$ is negative somewhere, whereas the outward flow of Task 11 is never negative. The dipole points inward over part of space; it returns. That is the numerical signature of a field closing on itself. ::: ### Task 12 — three flows -Three velocity fields. For each: **sketch it in your head, predict the sign of the divergence, then measure.** Write the predictions down first — the point of this task is the gap between intuition and the answer. +Three velocity fields. For each one: **sketch it, predict the sign of the divergence, then measure.** Record the predictions first; the task is about the gap between intuition and the result. | | Field $\boldsymbol{A}$ | What it looks like | | :---: | :--- | :--- | -| **(a)** | $x\,\hat{\boldsymbol{x}} + y\,\hat{\boldsymbol{y}} + z\,\hat{\boldsymbol{z}}$ | flow rushing outward in all directions | +| **(a)** | $x\,\hat{\boldsymbol{x}} + y\,\hat{\boldsymbol{y}} + z\,\hat{\boldsymbol{z}}$ | outward flow in all directions | | **(b)** | $-y\,\hat{\boldsymbol{x}} + x\,\hat{\boldsymbol{y}}$ | fluid rotating about the $z$-axis | | **(c)** | $x\,\hat{\boldsymbol{x}} - y\,\hat{\boldsymbol{y}}$ | stretching along $x$, squeezing along $y$ | ```{code-cell} ipython3 -# Commit to your predictions BEFORE the next cell: +1 for a source, -1 for a -# sink, 0 for solenoidal. The next cell scores them. +# Record the predictions BEFORE running the next cell: +1 for a source, +# -1 for a sink, 0 for solenoidal. The next cell scores them. predictions = {"a": ___, "b": ___, "c": ___} ``` @@ -1120,13 +1119,13 @@ for ax_, (name, A, d) in zip(axes, [("(a) outward flow", Aa, div_a), label=r"$\nabla\cdot\boldsymbol{A}$ [s$^{-1}$]", title=name) plt.tight_layout() plt.show() -# Look hard at (b) and (c) before reading the note below: both come out a -# uniform zero, and they get there for completely different reasons. +# Examine (b) and (c) before reading the note below: both come out a uniform +# zero, for entirely different reasons. # --- self-check (leave this alone) --- -# (a) has a non-zero answer, so a relative test works. (b) and (c) are -# exactly zero, which nothing can be measured *relative* to -- those get an -# absolute tolerance instead. +# (a) has a non-zero answer, so a relative test works. (b) and (c) are exactly +# zero, and nothing can be measured relative to zero, so they get an absolute +# tolerance instead. fw.check_close("(a) div = 3", div_a, 3.0, rtol=1e-6) fw.check_abs("(b) div = 0 (rotation)", div_b, atol=1e-9) fw.check_abs("(c) div = 0 (shear)", div_c, atol=1e-9) @@ -1151,16 +1150,16 @@ div_c = divergence(*Ac, dx, dy, dz) ``` ::: -:::{admonition} Field (c) is the one that costs marks +:::{admonition} Field (c) is the trap :class: warning -Along the $x$-axis, field (c) rushes outward. It looks like a source. It is not: +Along the $x$-axis, field (c) flows outward and resembles a source. It is not: $$ \nabla\cdot\boldsymbol{A} = \frac{\partial}{\partial x}(x) + \frac{\partial}{\partial y}(-y) = 1 - 1 = 0 $$ -Put a box at the origin: fluid pours out through the left and right walls and in through the top and bottom at exactly the same rate. The parcel changes **shape**, never **volume**. +Place a box at the origin: fluid leaves through the left and right walls and enters through the top and bottom at exactly the same rate. The parcel changes **shape**, not **volume**. -*Arrows pointing apart* is not divergence. Outflow in one direction can be cancelled exactly by inflow in another — and in Task 14 you will put a closed surface around this field and measure that cancellation, rather than take it on the strength of this paragraph. +Diverging arrows are not divergence. Outflow in one direction can be cancelled exactly by inflow in another. Task 14 puts a closed surface around this field and measures the cancellation directly. ::: ### Task 13 — the divergence as a charge detector @@ -1169,23 +1168,23 @@ Gauss's law, for a field in vacuum, says $$ \nabla\cdot\boldsymbol{E} = \frac{\rho_v}{\varepsilon_0} $$ -which is a strong claim: **the divergence of $\boldsymbol{E}$ at a point tells you the charge density at that point and nothing else.** Wherever there is no charge, $\boldsymbol{E}$ is solenoidal, however dramatically its arrows spread out. +which is a strong claim: **the divergence of $\boldsymbol{E}$ at a point gives the charge density at that point and nothing else.** Where there is no charge, $\boldsymbol{E}$ is solenoidal, however widely its arrows spread. -Test that pointwise on a real source. Not a point charge — that is an idealisation with infinite density at one location, and no grid can hold it. Take instead a charge **smeared over a finite blob**, which is what any actual charged object is: +Test that pointwise, on a source a grid can hold. A point charge cannot serve: it has infinite density at one location. Take instead a charge **distributed over a finite blob**, which is what any real charged object is: $$ \rho_v(r) = \rho_{v0}\,e^{-r^{2}/a^{2}}, \qquad \rho_{v0} = 10^{-9}\ \text{C/m}^3, \qquad a = 0.5\ \text{m} $$ -Here $a$ is the **width of the blob**. In Task 9 the same letter was an electrode separation — the second overloaded symbol on this page, after $\rho$. The code keeps them apart as `a` and `a_sep`; your algebra has only the context to go on. +Here $a$ is the **width of the blob**. In Task 9 the same letter denoted an electrode separation, the second overloaded symbol on this page after $\rho$. The code keeps them apart as `a` and `a_sep`; in algebra only the context distinguishes them. -Integrating that over a sphere of radius $r$ gives the charge it encloses (bookwork — you do not need to do the integral now): +Integrating over a sphere of radius $r$ gives the charge it encloses: $$ Q_{\text{enc}}(r) = \int_0^{r}\!\rho_v\,4\pi r'^{2}\,dr' = 4\pi\rho_{v0}\left[\frac{a^{3}\sqrt{\pi}}{4}\operatorname{erf}\!\left(\frac{r}{a}\right) - \frac{a^{2}r}{2}e^{-r^{2}/a^{2}}\right] $$ -and Gauss's law, $E_r = Q_{\text{enc}}/4\pi\varepsilon_0r^{2}$, then gives the field — the $4\pi$ cancelling: +and Gauss's law, $E_r = Q_{\text{enc}}/4\pi\varepsilon_0r^{2}$, then gives the field, with the $4\pi$ cancelling: $$ E_r(r) = \frac{\rho_{v0}}{\varepsilon_0 r^{2}}\left[\frac{a^{3}\sqrt{\pi}}{4}\operatorname{erf}\!\left(\frac{r}{a}\right) - \frac{a^{2}r}{2}e^{-r^{2}/a^{2}}\right] $$ -One sanity check: near the centre $Q_{\text{enc}}$ grows as $r^{3}$ while the surface grows as $r^{2}$, so $E_r \to \rho_{v0} r/3\varepsilon_0$ — zero at the centre, rising linearly, peaking at $r \approx a$. +One check: near the centre $Q_{\text{enc}}$ grows as $r^{3}$ while the surface grows as $r^{2}$, so $E_r \to \rho_{v0} r/3\varepsilon_0$, zero at the centre, rising linearly, and peaking at $r \approx a$. ```{code-cell} ipython3 from scipy.special import erf @@ -1193,10 +1192,9 @@ from scipy.special import erf a, rho_v0 = 0.5, 1e-9 # --- given: the charge density, and the field Gauss's law gives it --- -# (Transcribing the erf expression teaches nothing; deciding what to do with -# it does. The two bracketed terms nearly cancel for r << a, so the closed -# form loses accuracy below r ~ 1e-6 m; on this grid the only such sample is -# the origin, where the r-hat components are zero anyway.) +# The two bracketed terms nearly cancel for r << a, so the closed form loses +# accuracy below r ~ 1e-6 m. On this grid the only such sample is the origin, +# where the r-hat components are zero in any case. rho_v = rho_v0 * np.exp(-r**2 / a**2) E_r = rho_v0 / (epsilon_0 * rs**2) * ( (a**3 * np.sqrt(np.pi) / 4) * erf(rs / a) - (a**2 * rs / 2) * np.exp(-rs**2 / a**2) @@ -1238,17 +1236,17 @@ div_blob = divergence(Ex_b, Ey_b, Ez_b, dx, dy, dz) ``` ::: -:::{admonition} What you just did +:::{admonition} What the two panels show :class: important -The two pictures are the same picture. You never told the code where the charge was — you handed it a *field*, differentiated it, and the charge distribution came back out. +The two panels show the same distribution. The location of the charge was never supplied to the code: a field was differentiated, and the charge distribution came back out. -Notice where the divergence vanishes: everywhere outside the blob, where the field is still large and still spreading. **Strong field, zero divergence** — the two ideas are unrelated. +Note where the divergence vanishes: everywhere outside the blob, where the field is still large and still spreading. **Strong field, zero divergence**: the two quantities are unrelated. ::: ### The same operator, a different formula -Everything so far used the Cartesian formula, because `np.gradient` differentiates along array axes. But the divergence *is* flux per unit volume — a physical quantity, which cannot depend on the axes you happened to choose. Only the formula changes: +Everything so far used the Cartesian formula, because `np.gradient` differentiates along array axes. The divergence is flux per unit volume, a physical quantity that cannot depend on the choice of axes. Only the formula changes: | | Gradient $\nabla T$ | Divergence $\nabla\cdot\boldsymbol{A}$ | | :--- | :--- | :--- | @@ -1258,9 +1256,9 @@ Everything so far used the Cartesian formula, because `np.gradient` differentiat Cylindrical $\varrho=\sqrt{x^2+y^2}$ is the distance from the $z$-axis; spherical $r=\sqrt{x^2+y^2+z^2}$, used throughout this lab, is the distance from the origin. They are written differently precisely to keep them apart. -One reading note: the spherical coordinates are *named* $(r,\phi,\theta)$, but the terms in the row above are listed $r$, then $\theta$, then $\phi$ — the order in which the scale factors $(1,\ r,\ r\sin\theta)$ are derived. A sum does not care about the order of its terms; only about which ones are in it. +One reading note: the spherical coordinates are named $(r,\phi,\theta)$, but the terms in the row above are listed as $r$, then $\theta$, then $\phi$, the order in which the scale factors $(1,\ r,\ r\sin\theta)$ are derived. The order of terms in a sum is immaterial. -Both fields you have built are spherically symmetric — $\boldsymbol{E} = E_r(r)\,\hat{\boldsymbol{r}}$, with no $\theta$ or $\phi$ dependence — so two of the three spherical terms vanish and the divergence collapses to one ordinary derivative along one line: +Both fields built so far are spherically symmetric, $\boldsymbol{E} = E_r(r)\,\hat{\boldsymbol{r}}$ with no $\theta$ or $\phi$ dependence, so two of the three spherical terms vanish and the divergence reduces to one ordinary derivative along one line: $$ \nabla\cdot\boldsymbol{E} \;=\; \frac{1}{r^{2}}\frac{d}{dr}\!\left(r^{2}E_r\right) $$ @@ -1302,27 +1300,27 @@ print(f"point: r^2 E_r varies by {np.ptp(r_line**2 * E_r_point):.1e} over the wh print(f" max |div E| = {np.abs(div_point_sph).max():.1e} (round-off, not physics)") ``` -:::{admonition} Why anyone bothers with curvilinear coordinates +:::{admonition} Why curvilinear coordinates are worth the trouble :class: important -Same field, same operator, same answer — from a few hundred samples on a line instead of a quarter of a million in a cube, and several times more accurately. +Same field, same operator, same answer, obtained from a few hundred samples on a line rather than a quarter of a million in a cube, and several times more accurately. -For the point charge the gain is not accuracy but certainty. $r^{2}E_r = Q/4\pi\varepsilon_0$ is a **constant**, so its derivative is *analytically* zero for every $r>0$ — not "1% of something", but zero, by one line of algebra. What the cell prints is only how well double precision can subtract two equal numbers: $10^{-13}$ or so, and exactly $0$ if the arithmetic happens to cancel. Change `dr` and that last digit will move; the algebra will not. Cartesian coordinates could never have got past "the divergence is small". +For the point charge the gain is certainty rather than accuracy. $r^{2}E_r = Q/4\pi\varepsilon_0$ is a **constant**, so its derivative is analytically zero for every $r>0$: not 1% of something, but zero, in one line of algebra. What the cell prints is the precision with which double arithmetic subtracts two equal numbers, around $10^{-13}$, or exactly $0$ when the cancellation is exact. Changing `dr` moves that last digit; it does not move the algebra. Cartesian coordinates could establish only that the divergence is small. -Match your coordinates to the symmetry of the source and three noisy numerical derivatives collapse into one line of algebra. That is what the second and third rows of the table are for. +Matching the coordinates to the symmetry of the source replaces three noisy numerical derivatives with one line of algebra. That is the purpose of the second and third rows of the table. ::: --- ## Part 6 — Flux, and the divergence theorem -Part 5 used the *differential* form of Gauss's law, which compares two numbers at one point. The *integral* form connects a volume to the surface enclosing it: +Part 5 used the differential form of Gauss's law, which compares two numbers at one point. The integral form relates a volume to the surface enclosing it: $$ \oint_S \boldsymbol{E}\cdot\hat{\boldsymbol{n}}\,dS \;=\; \int_{\mathcal{D}} \nabla\cdot\boldsymbol{E}\;dV \;=\; \frac{Q_{\text{enc}}}{\varepsilon_0} $$ with $S$ the closed surface, $\hat{\boldsymbol{n}}$ its outward unit normal, and $\mathcal{D}$ the volume it encloses. -The first equality is the **divergence theorem** — pure vector calculus, true for any well-behaved field. The second is the physics. Together: measuring $\boldsymbol{E}$ on a closed surface tells you how much charge is inside, and nothing about how it is arranged, or about any charge outside. +The first equality is the **divergence theorem**, pure vector calculus, valid for any well-behaved field. The second is the physics. Together they state that measuring $\boldsymbol{E}$ on a closed surface gives the charge inside, and nothing about its arrangement or about any charge outside. Take $S$ to be a cube of half-width $h$ centred on the origin, faces on grid planes. On the $+x$ face the outward normal is $+\hat{\boldsymbol{x}}$, so it contributes $\int\!\!\int E_x\,dy\,dz$; on the $-x$ face the normal is $-\hat{\boldsymbol{x}}$ and the same integral enters negatively. Six faces, three pairs. @@ -1341,8 +1339,8 @@ Take $S$ to be a cube of half-width $h$ centred on the origin, faces on grid pla # z Az[s, s, i1] Az[s, s, i0] dx, dy # # The axis you pin to i0/i1 is the axis whose spacing you leave out. -# NOTE: this closes over X, dx, dy, dz from the cell above -- it is tied to -# this grid, not a general-purpose function. +# NOTE: this closes over X, dx, dy, dz from the cell above, so it is tied to +# this grid and is not a general-purpose function. def closed_box_flux(Ax, Ay, Az, half_width): """Net outward flux through the cube |x|,|y|,|z| <= half_width.""" @@ -1369,8 +1367,8 @@ for h in (0.6, 1.0, 1.4): print(f"{h:6.1f} {surf:12.3f} {vol:12.3f} {qenc:12.3f}") # Task 12 settled by measurement rather than by argument. Both (b) and (c) -# look like they throw fluid outwards somewhere; a closed surface is the -# arbiter, and it never had to differentiate anything. +# appear to throw fluid outwards somewhere; a closed surface is the arbiter, +# and it differentiates nothing. print(f"\nflux of (b), the rotation : {closed_box_flux(-Y, X, zero, 1.0):+.2e}") print(f"flux of (c), the shear : {closed_box_flux(X, -Y, zero, 1.0):+.2e}") @@ -1400,16 +1398,16 @@ fw.check_scalar("divergence theorem: surface = volume", flux_1m, :::{admonition} Three routes, one number :class: important -Three genuinely different calculations. The first never looks inside the box; the second never looks at the surface; the third never looks at the field at all. They agree to a fraction of a percent. +Three independent calculations. The first never examines the interior of the box, the second never examines the surface, and the third never examines the field. They agree to a fraction of a percent. -The number grows with $h$ and then stops: once the cube holds essentially all the charge, enlarging it adds surface but no charge. Charge outside a closed surface contributes exactly nothing — the field lines it sends in through one wall leave through another. +The result grows with $h$ and then stops: once the cube holds nearly all the charge, enlarging it adds surface but no charge. Charge outside a closed surface contributes exactly nothing, because the field lines it sends in through one wall leave through another. ::: -### And now shrink the source to a point +### Shrinking the source to a point -Run the same surface integral on the point-charge field from Task 7 — the one whose divergence you could never measure at the origin, because you had to mask it away. +Run the same surface integral on the point-charge field of Task 7, whose divergence could not be measured at the origin because the singularity had to be masked. -Rearranged, Gauss's law turns your flux into a **charge meter**: $Q_{\text{enc}} = \varepsilon_0 \oint_S \boldsymbol{E}\cdot\hat{\boldsymbol{n}}\,dS$. So weigh the charge inside each box, in coulombs, and compare it with the 1 nC you put there. +Rearranged, Gauss's law turns the flux into a **charge meter**: $Q_{\text{enc}} = \varepsilon_0 \oint_S \boldsymbol{E}\cdot\hat{\boldsymbol{n}}\,dS$. Weigh the charge inside each box in coulombs and compare it with the 1 nC placed there. ```{code-cell} ipython3 print("box half-width charge it finds") @@ -1418,9 +1416,9 @@ for h in (0.6, 1.0, 1.4): print(f" {h:.1f} m {Q_found * 1e12:8.2f} pC") print(f"\n actually there {Q * 1e12:8.2f} pC") -# The shell between the 0.6 m and 1.4 m boxes holds no charge at all. Weigh it: -# what enters the small box must leave the large one, so the difference of the -# two fluxes is the charge in between. +# The shell between the 0.6 m and 1.4 m boxes holds no charge. Weigh it: what +# enters the small box must leave the large one, so the difference of the two +# fluxes is the charge in between. Q_shell = epsilon_0 * (closed_box_flux(Ex, Ey, Ez, 1.4) - closed_box_flux(Ex, Ey, Ez, 0.6)) print(f"\ncharge in the shell between them: {Q_shell * 1e12:+.2f} pC " @@ -1430,23 +1428,22 @@ print(f"\ncharge in the shell between them: {Q_shell * 1e12:+.2f} pC " :::{admonition} Where did the charge go? :class: important -Every box weighs the same 1 nC, to a fraction of a percent — and the shell between two of them weighs nothing. All the charge is in the only region every box has in common: the origin. +Every box weighs the same 1 nC to a fraction of a percent, and the shell between two of them weighs nothing. All the charge lies in the only region common to every box: the origin. -So the whole source sits at one point, where $\nabla\cdot\boldsymbol{E}$ is not a large number but no number at all: $\rho_v$ has become a **Dirac delta**, zero everywhere, infinite at one point, with a finite integral $Q$. The integral form survives exactly where the differential form breaks down. +The whole source therefore sits at one point, where $\nabla\cdot\boldsymbol{E}$ is not a large number but undefined: $\rho_v$ has become a **Dirac delta**, zero everywhere, infinite at one point, with finite integral $Q$. The integral form survives exactly where the differential form fails. The same statement for magnetism carries no source term at all: $$ \nabla\cdot\boldsymbol{B} = 0 \qquad\Longleftrightarrow\qquad \oint_S \boldsymbol{B}\cdot\hat{\boldsymbol{n}}\,dS = 0 \ \ \text{for every closed } S $$ -Run this measurement around any closed surface anywhere and you get zero: there are no magnetic monopoles, and field lines of $\boldsymbol{B}$ never begin and never end. +The measurement returns zero around any closed surface anywhere: there are no magnetic monopoles, and field lines of $\boldsymbol{B}$ never begin or end. ::: -### And the dipole, exactly +### The dipole, exactly -Task 11 measured $\nabla\cdot\boldsymbol{B} = 0$ for the Earth's dipole and got 1.8% — grid error, not physics. Now make the same claim without differentiating anything: put a closed surface around the dipole and weigh what comes out. +Task 11 measured $\nabla\cdot\boldsymbol{B} = 0$ for the Earth's dipole and returned 1.8%, which is grid error rather than physics. The same claim can be tested without differentiating: put a closed surface around the dipole and weigh what crosses it. -One warning before you read the numbers. A box centred on the origin is a -suspiciously easy test for *this* dipole: with $\boldsymbol{m} = \hat{\boldsymbol{z}}$, $B_x$ and $B_y$ are odd in $z$ and $B_z$ is even, so on a $z$-symmetric box the faces cancel in pairs *before* any physics enters. A lopsided box is the honest one, so the cell below runs both. +One warning before reading the numbers. A box centred on the origin is too easy a test for this dipole: with $\boldsymbol{m} = \hat{\boldsymbol{z}}$, $B_x$ and $B_y$ are odd in $z$ and $B_z$ is even, so on a $z$-symmetric box the faces cancel in pairs before any physics enters. An off-centre box is the honest test, and the cell below runs both. ```{code-cell} ipython3 r_dot_m = Z @@ -1488,16 +1485,16 @@ fw.check("...and the same integrator does find the tap in the radial flow", :::{admonition} Two kinds of "divergence-free" :class: important -The radial flow returns $4\pi$ through every surface, whatever its size — there is a tap at the origin, and every box finds the same one, exactly as every box found the same 1 nC a moment ago. +The radial flow returns $4\pi$ through every surface, whatever its size: there is a tap at the origin, and every box finds the same one, as every box found the same 1 nC above. -The dipole returns **nothing**, through any of them. On the three centred boxes the answer is zero to machine precision — but read that with the warning above in mind: those boxes cancel the field against itself by symmetry, so they were never going to say anything else. The lopsided boxes are the measurement that counts, and they return $-2.5\times10^{-3}$ and $-2.2\times10^{-4}$. That sounds like a retreat until you put it beside the column next to it: the very same integrator, on the very same grid, misses $4\pi$ by $6.8\times10^{-3}$ on the radial flow. **The dipole's flux is zero to better than the accuracy with which this method can measure anything at all.** +The dipole returns **nothing** through any of them. On the three centred boxes the result is zero to machine precision, but the warning above applies: those boxes cancel the field against itself by symmetry and could return nothing else. The off-centre boxes are the measurement that counts, and they return $-2.5\times10^{-3}$ and $-2.2\times10^{-4}$. Compare the adjacent column: the same integrator, on the same grid, misses $4\pi$ by $6.8\times10^{-3}$ on the radial flow. **The flux of the dipole is zero to better than the accuracy this method achieves on anything.** -So the two "divergence-free" fields are not the same statement. The flow has a tap you can find by shrinking a surface onto it; the dipole has nothing to find, at any size or placement of the surface. That is $\nabla\cdot\boldsymbol{B} = 0$ in the form that admits no exception, and it is why the integral form was worth building: it settles matters *at* the source, where the differential form had to be masked away. +The two divergence-free fields are therefore different statements. The flow has a tap that can be located by shrinking a surface onto it; the dipole has nothing to locate, at any size or placement of the surface. This is $\nabla\cdot\boldsymbol{B} = 0$ in the form that admits no exception, and it is why the integral form is worth constructing: it settles the question at the source, where the differential form had to be masked. ::: ### Where do the 1% errors come from? -Every derivative on this page is a centred difference, accurate to $O(\Delta x^{2})$. That is a law, not an excuse: halve the spacing and the error should fall by four. Confirm it — the whole study is one loop. +Every derivative on this page is a centred difference, accurate to $O(\Delta x^{2})$: halving the spacing should reduce the error by four. Confirm it. The study is a single loop. ```{code-cell} ipython3 print(f"{'n':>4} {'dx [m]':>8} {'worst error':>12} {'ratio':>7}") @@ -1524,25 +1521,25 @@ for n_test in (21, 31, 41, 61): :::{admonition} Second order, by measurement :class: important -Compare each ratio with the square of the spacing ratio — $1.5^2 = 2.25$ from $n=21$ to $31$, $1.33^2 = 1.78$ from $31$ to $41$, $1.5^2 = 2.25$ from $41$ to $61$. +Compare each ratio with the square of the spacing ratio: $1.5^2 = 2.25$ from $n=21$ to $31$, $1.33^2 = 1.78$ from $31$ to $41$, and $1.5^2 = 2.25$ from $41$ to $61$. -So the 1.06% in Task 13 is not noise to be tolerated: it is a number you can predict, and buy down if you need to. And the choice of $n = 61$ in Part 2 is now yours to audit rather than take on trust. +The 1.06% in Task 13 is therefore not noise to be tolerated but a predictable quantity that can be reduced at a known cost, and the choice of $n = 61$ in Part 2 can now be audited rather than assumed. ::: --- ## Closing -Today's chain, in one line: +The chain built in this lab, in one line: $$ \rho_v \;\longrightarrow\; V \;\xrightarrow{\ -\nabla\ }\; \boldsymbol{E} \;\xrightarrow{\ \nabla\cdot\ }\; \rho_v/\varepsilon_0 $$ -- **Gradient** — scalar in, vector out. Points along steepest increase, perpendicular to the level surfaces, with length equal to the rate of increase. -- **Divergence** — vector in, scalar out. Net flux per unit volume: what is being created here, and nothing else. +- **Gradient.** Scalar in, vector out. Points along steepest increase, normal to the level surfaces, with length equal to the rate of increase. +- **Divergence.** Vector in, scalar out. Net flux per unit volume, which measures what is created at a point and nothing else. ### The same two operators, elsewhere in ECT -Electrostatics is the convenient place to *learn* this pair, not the only place to use it. Every row below is a potential, its gradient, and a statement about sources — and the numerical machinery you wrote today applies unchanged to all of them: +Electrostatics is a convenient place to learn this pair, not the only place to use it. Each row below gives a potential, its gradient, and a statement about sources. The numerical machinery written in this lab applies unchanged to all of them: | System | Potential | Field | Source equation | | :--- | :--- | :--- | :--- | @@ -1555,25 +1552,25 @@ with $k$ the thermal conductivity [W m$^{-1}$ K$^{-1}$] and $K$ the hydraulic co The minus signs are all the same minus sign: heat flows from hot to cold, water flows from high head to low, a positive charge falls from high potential to low. Flow runs downhill, and the gradient points uphill. -The last two rows are why a solenoidal field matters so much in practice. $\nabla\cdot\boldsymbol{q} = 0$ in an aquifer is not an approximation of convenience — it is conservation of water written locally. +The last two rows show why solenoidal fields matter in practice. $\nabla\cdot\boldsymbol{q} = 0$ in an aquifer is not an approximation of convenience; it is conservation of water written locally. ### What is still missing -Go back to field **(b)**, the rotation. Its divergence is zero everywhere, so by that measure it is indistinguishable from a field doing nothing at all. But it plainly *is* doing something — it circulates, and every streamline closes on itself. +Return to field **(b)**, the rotation. Its divergence is zero everywhere, so by that measure it is indistinguishable from a field doing nothing. It nevertheless circulates, and every streamline closes on itself. -Divergence cannot see circulation. The operator that can is the **curl**, the third of the three this chapter is named after. +The divergence cannot detect circulation. The operator that can is the **curl**, the third of the three operators this chapter is named after. ### Homework -The exercises in your lecture notes are the written homework. Below is the lab's own extension — the one piece that is computational rather than pen-and-paper, and that carries the afternoon's operators into a system you can feel. +The exercises in the lecture notes are the written homework. Below is the lab's computational extension, which carries the same two operators into a different physical system. -**A heat source in a room.** Replace the spherical blob with a flat rectangular heater, $1.0 \times 0.6$ m in the $z = 0$ plane. A steady point source of power $P$ in a medium of conductivity $k$ raises the temperature above ambient by $P/4\pi k r$ — the same $1/r$ you have worked with all afternoon. Split the plate into $N = 20 \times 12$ sub-sources, give each an equal share $P/N$ of the power, and superpose, exactly as you superposed two charges in Task 8: +**A heat source in a room.** Replace the spherical blob with a flat rectangular heater, $1.0 \times 0.6$ m in the $z = 0$ plane. A steady point source of power $P$ in a medium of conductivity $k$ raises the temperature above ambient by $P/4\pi k r$, the same $1/r$ used throughout this lab. Split the plate into $N = 20 \times 12$ sub-sources, give each an equal share $P/N$ of the power, and superpose them as two charges were superposed in Task 8: $$ T(\boldsymbol{r}) = \frac{P}{4\pi k N}\sum_{i=1}^{N} \frac{1}{\lvert \boldsymbol{r} - \boldsymbol{r}_i \rvert}, \qquad P = 100\ \text{W}, \qquad k_{\text{air}} = 0.026\ \text{W m}^{-1}\text{K}^{-1}. $$ -Check the dimensions before you code it: $[P]/[k] = \text{W}/(\text{W m}^{-1}\text{K}^{-1}) = \text{m}\cdot\text{K}$, divided by a distance, so $T$ comes out in kelvin. A formula for a temperature that does not is a formula with a bug in it. Then: +Check the dimensions before coding: $[P]/[k] = \text{W}/(\text{W m}^{-1}\text{K}^{-1}) = \text{m}\cdot\text{K}$, divided by a distance, so $T$ comes out in kelvin. A temperature formula that does not reduce to kelvin contains an error. Then: -- Plot the isosurfaces. Close to the plate they should be rounded rectangles; far away they should become spheres. Why does the shape forget its source? -- Compute the heat flux $\boldsymbol{q}_T = -k\nabla T$ — the same minus sign, the same reason as $\boldsymbol{E} = -\nabla V$. -- Check that $\nabla\cdot\boldsymbol{q}_T \approx 0$ away from the heater, and that the closed-surface flux through a box containing the plate is *not* zero. Say what each result means physically for a room at steady state, and which of the two fields you met in Task 11 the heater resembles. -- **Then look at the number.** One metre from a 100 W panel this model predicts about $+290$ K above ambient — a room at 300 °C. The arithmetic is right, so the *physics* is wrong. Which assumption failed? (Two are worth naming: what actually carries heat through air, and where this solution puts the room's walls.) Re-run it with $k = 1.5$ W m⁻¹K⁻¹, the conductivity of soil, and you get $+5$ K — the same equations, now describing a buried heating element, which is a problem pure conduction really does solve. +- Plot the isosurfaces. Close to the plate they should be rounded rectangles; far away they should become spheres. Explain why the shape loses the imprint of its source. +- Compute the heat flux $\boldsymbol{q}_T = -k\nabla T$, with the same minus sign and the same reason as $\boldsymbol{E} = -\nabla V$. +- Check that $\nabla\cdot\boldsymbol{q}_T \approx 0$ away from the heater, and that the closed-surface flux through a box containing the plate is *not* zero. State what each result means physically for a room at steady state, and which of the two fields in Task 11 the heater resembles. +- **Then examine the number.** One metre from a 100 W panel this model predicts about $+290$ K above ambient, a room at 300 °C. The arithmetic is correct, so the physics is wrong. Identify the failed assumption; two are worth naming, namely what actually transports heat through air, and where this solution places the walls of the room. Re-running with $k = 1.5$ W m⁻¹K⁻¹, the conductivity of soil, gives $+5$ K: the same equations now describe a buried heating element, a problem that pure conduction does solve. From 49b887affe5c78481ded59b48cfcfdb0d7e142d8 Mon Sep 17 00:00:00 2001 From: ARS183 <1028762817@qq.com> Date: Tue, 1 Sep 2026 23:20:24 +0200 Subject: [PATCH 08/17] Cut redundant prose from the Week 1 lab --- .../labs/week01-grad-div.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/book/1_gradient_divergence_curl/labs/week01-grad-div.md b/book/1_gradient_divergence_curl/labs/week01-grad-div.md index 12a4779..6455486 100644 --- a/book/1_gradient_divergence_curl/labs/week01-grad-div.md +++ b/book/1_gradient_divergence_curl/labs/week01-grad-div.md @@ -323,11 +323,11 @@ $$ r(x,y,z) = \sqrt{(x-x_0)^2 + (y-y_0)^2 + (z-z_0)^2} $$ One number at every location in space: no charge, no potential, and no units beyond metres. -This is the **spherical** radial coordinate $r$, the distance from a point. The cylindrical radius $\varrho$, the distance from an axis, is a different quantity, and Part 5 returns to the distinction. The equations on this page use $r$, and the code calls it `r`, because it is the only radius in the lab. +This is the **spherical** radial coordinate $r$, the distance from a point. The cylindrical radius $\varrho$, the distance from an axis, is a different quantity. The equations on this page use $r$, and the code calls it `r`. ### Task 3 — build the distance field -**The question:** what do the surfaces of constant $r$ look like, and where do they crowd together? Answer before computing. This is the one field on the page that can be pictured completely in advance. +**The question:** what do the surfaces of constant $r$ look like, and where do they crowd together? The source must be movable: Task 8 places two of them at different points, so write the offsets in now rather than hard-coding the origin. @@ -362,7 +362,7 @@ r = distance_to(X, Y, Z) ``` ::: -A surface on which $r$ takes one fixed value is an **isosurface**, or level set, the three-dimensional analogue of a contour line on a map. Drag the opacity slider under the figure until the inner shells are visible through the outer one. Evenly spaced values of $r$ give evenly spaced shells: the distance function has no preferred radius, which is why its gradient is so simple in the next task. +A surface on which $r$ takes one fixed value is an **isosurface**, or level set, the three-dimensional analogue of a contour line on a map. Evenly spaced values of $r$ give evenly spaced shells: the distance function has no preferred radius. ```{code-cell} ipython3 fw.show_isosurfaces(X, Y, Z, r, levels=[0.5, 1.0, 1.5], label="r [m]", @@ -382,7 +382,7 @@ $$ \nabla r \;=\; \frac{\partial r}{\partial x}\hat{\boldsymbol{x}} + \frac{\par The last step is the definition of the outward unit radial vector: $\hat{\boldsymbol{r}}$ is the position vector divided by its own length. So $\nabla r$ is a **unit** vector pointing **away** from the source, with both direction and magnitude known in advance. -The cell below tests whether a finite-difference gradient on a grid reproduces that. Two measurements: the magnitude, which should be 1, and the projection $\nabla r \cdot \hat{\boldsymbol{r}}$, which recovers the full magnitude only if the gradient is purely radial, with no component along the sphere. +The cell below tests whether a **finite-difference gradient** on a grid reproduces that. Two measurements: the magnitude, which should be 1, and the projection $\nabla r \cdot \hat{\boldsymbol{r}}$, which recovers the full magnitude only if the gradient is purely radial, with no component along the sphere. ```{code-cell} ipython3 # The outward unit radial vector, used again later. @@ -439,7 +439,6 @@ $\lvert\nabla r\rvert = 1$ needs no calculus: move one metre directly away from The radial check fixes the other half: moving along a sphere does not change $r$, so the gradient has no component there. **$\nabla f$ is normal to the level surfaces of $f$** for every scalar field, not only this one. -The same chain rule settles the next two tasks in advance: $\nabla g(r) = \dfrac{dg}{dr}\,\hat{\boldsymbol{r}}$ for any $g$ depending on position only through $r$. Derive it before running the cells. ::: ### Task 5 — the rate of change in an arbitrary direction @@ -598,7 +597,7 @@ $\nabla V$ points inward, uphill towards the charge. The minus sign reverses it, ```{code-cell} ipython3 V = k_e * Q / r_masked -# Task 7 -- two blanks. Mind the minus sign; it is the whole task. +# Task 7 -- two blanks. Mind the minus sign. Ex, Ey, Ez = ___ # E = -grad V E_mag = ___ From 2410b7f59343971a7654c4a422bc0321854581e0 Mon Sep 17 00:00:00 2001 From: ARS183 <1028762817@qq.com> Date: Wed, 2 Sep 2026 00:05:22 +0200 Subject: [PATCH 09/17] Split the lab into two notebooks, one per session, each numbered from the start --- .../labs/week01-grad-div.md | 1575 ----------------- .../labs/week01_series_grad.md | 882 +++++++++ .../labs/week02_div_curl.md | 826 +++++++++ book/_toc.yml | 3 +- 4 files changed, 1710 insertions(+), 1576 deletions(-) delete mode 100644 book/1_gradient_divergence_curl/labs/week01-grad-div.md create mode 100644 book/1_gradient_divergence_curl/labs/week01_series_grad.md create mode 100644 book/1_gradient_divergence_curl/labs/week02_div_curl.md diff --git a/book/1_gradient_divergence_curl/labs/week01-grad-div.md b/book/1_gradient_divergence_curl/labs/week01-grad-div.md deleted file mode 100644 index 6455486..0000000 --- a/book/1_gradient_divergence_curl/labs/week01-grad-div.md +++ /dev/null @@ -1,1575 +0,0 @@ ---- -jupytext: - text_representation: - extension: .md - format_name: myst - format_version: 0.13 -kernelspec: - display_name: Python 3 (ipykernel) - language: python - name: python3 -mystnb: - # Workbook page: the task cells contain `___` blanks by design, so it must - # not be executed at build time. Readers run it themselves with Live Code. - execution_mode: 'off' ---- - -# Lab: Gradient and Divergence - -:::{admonition} Computer lab -:class: note - -A practical companion to the lectures on the gradient and the divergence. Each task states a physical question, gives the steps, and ends with a self-check you can run. Plotting is supplied in the module `fwtools`, so that your effort goes into the physics rather than into rendering transparent isosurfaces. -::: - -## Learning objectives - -By the end of this lab you should be able to: - -- **Truncate a series and quantify what the truncation costs.** Sum a geometric series, approximate it by its leading term, determine how many terms a given accuracy requires, and identify where a Taylor series ceases to converge. -- **Read a gradient off a figure.** Show that $\nabla r = \hat{\boldsymbol{r}}$, that $\nabla f$ is normal to the level surfaces of $f$, and that $dp/dl = \lvert\nabla p\rvert\cos\psi$, so that the magnitude of the gradient is the maximum rate of change. -- **Convert a potential into a field, and a field into a survey.** Apply $\boldsymbol{E} = -\nabla V$ and Ohm's law $\boldsymbol{J} = -\rho^{-1}\nabla V$, and map the potential and current density of a two-electrode DC resistivity measurement. -- **Distinguish diverging arrows from non-zero divergence.** Compute $\nabla\cdot\boldsymbol{v}$, justify the result by flux rather than by algebra, and identify the only radial flow that is incompressible. -- **Use the divergence theorem as a measurement.** Verify $\oint_S\boldsymbol{v}\cdot\hat{\boldsymbol{n}}\,dS = \int_{\mathcal{D}} \nabla\cdot\boldsymbol{v}\,dV$ numerically, and account for what happens when the source shrinks to a point. - -:::{admonition} Two sessions -:class: note - -**Session 1** runs to the end of Part 4 and covers the gradient. **Part 5 onwards belongs to the following session**, after the divergence has been lectured. Both sessions are on one page, so you can read ahead. -::: - ---- - -## Part 0 — Setup - -Run this once. It contains no physics: it fetches two packages the browser lacks, locates `fwtools`, and defines the Coulomb constant. - -```{code-cell} ipython3 -# No physics above the k_e = ... line near the bottom. -import sys, pathlib - -import numpy as np -import matplotlib.pyplot as plt -from scipy.constants import epsilon_0 - -# --- Live Code housekeeping, not part of the physics ----------------------- -try: - import plotly.io as pio -except ModuleNotFoundError: - print("Fetching plotly. A few seconds, and only the first time...") - import micropip - await micropip.install("plotly") - import plotly.io as pio - -try: - import nbformat # noqa: F401 -except ModuleNotFoundError: - import micropip, types - try: - await micropip.install("nbformat") - except Exception: - _nb = types.ModuleType("nbformat") - _nb.__version__ = "5.10.4" - sys.modules["nbformat"] = _nb - -for _p in (".", "book/1_gradient_divergence_curl/labs"): - if (pathlib.Path(_p) / "fwtools.py").exists(): - sys.path.insert(0, _p) - break -try: - import fwtools as fw -except ModuleNotFoundError: - from pyodide.http import pyfetch - _r = await pyfetch("fwtools.py") - pathlib.Path("fwtools.py").write_bytes(await _r.bytes()) - import fwtools as fw - -pio.renderers.default = "plotly_mimetype+notebook" -# --------------------------------------------------------------------------- - -k_e = 1.0 / (4.0 * np.pi * epsilon_0) # Coulomb constant, 8.99e9 V*m/C -Q = 1e-9 # 1 nC test charge - -print(f"epsilon_0 = {epsilon_0:.4e} F/m") -print(f"k_e = {k_e:.4e} V*m/C") -``` - ---- - -## Part 1 — Series and truncation - -A physical quantity is often an infinite sum, of which only the first few terms are kept. Two questions follow: what the truncation costs, and whether the sum converges at all. - -### Task 1 — the bouncing ball - -A ball leaves the ground at $z=0$ with upward velocity $v_0$. Between bounces it is in free fall, - -$$ z(t) = v_0 t - \tfrac{1}{2}g t^2, $$ - -so it returns to the ground after $T_0 = 2v_0/g$ having reached a height $H = v_0^2/2g$. At each bounce it loses a fraction $\gamma$ of its energy, so $v_n = \sqrt{1-\gamma}\;v_{n-1}$, and since flight time is proportional to launch speed, - -$$ T_n = (1-\gamma)^{n/2}\,T_0, \qquad T_0 = \sqrt{8H/g}. $$ - -Fill in the three physical lines; the plotting is given. - -```{code-cell} ipython3 -g, v0, gamma = 9.81, 5.0, 0.1 -N = 12 # bounces to draw - -H = ___ # peak height of the first flight -T0 = ___ # duration of the first flight -T = T0 * ___ # durations of bounces 0 .. N-1 - -# --- given: draw one parabola per bounce --- -t_start = np.concatenate(([0.0], np.cumsum(T)[:-1])) -plt.figure(figsize=(9, 3.4)) -for Tn, t0 in zip(T, t_start): - tau = np.linspace(0, Tn, 200) - plt.plot(t0 + tau, (g*Tn/2)*tau - g*tau**2/2, "C0") -plt.xlabel("$t$ [s]"); plt.ylabel("$z$ [m]"); plt.grid(alpha=0.3) -plt.title(f"bouncing ball, $\\gamma$ = {gamma}") -plt.show() - -# --- self-check (leave this alone) --- -fw.check(f"H = {H:.4f} m", np.isclose(H, v0**2/(2*g)), "H = v0^2 / 2g") -fw.check(f"T0 = {T0:.4f} s", np.isclose(T0, 2*v0/g), "T0 = 2 v0 / g") -fw.check("T0 = sqrt(8H/g) too", np.isclose(T0, np.sqrt(8*H/g))) -fw.check(f"{N} bounce durations, shrinking", len(T) == N and T[-1] < T[0]) -``` - -:::{admonition} Solution — Task 1 -:class: dropdown - -```python -H = v0**2 / (2*g) -T0 = 2*v0 / g -T = T0 * (1 - gamma)**(np.arange(N)/2) -``` -::: - -The ball bounces for a total time - -$$ T_\infty = \sum_{m=0}^{\infty} T_m = T_0\sum_{m=0}^{\infty}\left(\sqrt{1-\gamma}\right)^{m} = \frac{\sqrt{8H/g}}{1-\sqrt{1-\gamma}}, $$ - -a geometric series with ratio $\sqrt{1-\gamma}$. The ratio is smaller than 1 for any real bounce, so the sum is **finite**: infinitely many bounces, completed in about twenty seconds. The convergence condition matters, and Task 2 examines a series that fails it. For small $\gamma$, the expansion $\sqrt{1-\gamma}\approx 1-\gamma/2$ reduces the sum to - -$$ T_\infty \approx \sqrt{8H/g}\;\frac{2}{\gamma}. $$ - -Both questions are answered below by measurement: **how accurate is that approximation**, and **how many bounces must be summed** before the running total reaches $T_\infty$? - -```{code-cell} ipython3 -rows = {} -print(f"{'gamma':>7} {'T_inf':>9} {'approx':>9} {'error':>7} {'n for 99%':>10}") -for gam in (0.5, 0.2, 0.1, 0.02): - T_inf = ___ # the exact sum, from the formula above - T_appr = ___ # the small-gamma approximation - - # --- given: how many bounces to reach 99% of T_inf --- - rows[gam] = (T_inf, T_appr) - cum = np.cumsum(T0 * (1 - gam)**(np.arange(4000)/2)) - n99 = int(np.argmax(cum >= 0.99*T_inf)) + 1 - print(f"{gam:>7.2f} {T_inf:>8.3f}s {T_appr:>8.3f}s " - f"{abs(T_appr-T_inf)/T_inf:>6.1%} {n99:>10}") - -# --- self-check (leave this alone) --- -# The closed form against a brute-force sum of 5000 bounces: one number by -# two routes, one of which never assumed the series converges. -_summed = np.sum(T0 * (1 - 0.1)**(np.arange(5000)/2)) -fw.check(f"your T_inf at gamma = 0.1 ({rows[0.1][0]:.3f} s) equals the " - f"brute-force sum ({_summed:.3f} s)", - np.isclose(rows[0.1][0], _summed, rtol=1e-6)) -fw.check(f"your approximation overshoots by 2.6% there " - f"({rows[0.1][1]/rows[0.1][0] - 1:.2%})", - np.isclose(rows[0.1][1]/rows[0.1][0], 1.0263, rtol=1e-3)) -``` - -:::{admonition} Solution — Task 1, continued -:class: dropdown - -```python - T_inf = np.sqrt(8*H/g) / (1 - np.sqrt(1 - gam)) - T_appr = np.sqrt(8*H/g) * 2 / gam -``` -::: - -:::{admonition} What the table says -:class: important - -At $\gamma = 0.5$ the leading-term approximation is 17% wrong; at $\gamma = 0.02$ it is 0.5%. Keeping only the first term is a claim about the regime, not about the algebra, and it has to be justified case by case. - -The term count runs the other way. The more nearly elastic the ball, the more bounces the same accuracy requires: 14 at $\gamma = 0.5$, 456 at $\gamma = 0.02$. The approximation is cheapest exactly where the summation is most expensive. The same trade-off appears in every numerical method in this course. -::: - -### Task 2 — where a Taylor series stops working - -A function that is smooth enough, and whose series sums back to it, can be written as a Taylor series about $x=0$, - -$$ f(x) = f(0) + x f'(0) + \tfrac{1}{2}x^2 f''(0) + \cdots . $$ - -In practice the series is truncated after a few terms. Compare two cases: - -$$ \sin x = x - \frac{x^3}{3!} + \frac{x^5}{5!} - \cdots, \qquad\qquad \frac{1}{1+x} = 1 - x + x^2 - x^3 + \cdots $$ - -The two expansions look equally harmless. Add terms to each and compare. - -```{code-cell} ipython3 -x = np.linspace(-3, 3, 600) - -# term m of each series, as a function of x -def sin_term(m, x): - return 0.0 if m % 2 == 0 else ___ # (-1)^((m-1)/2) x^m / m! [math.factorial] - -def geo_term(m, x): - return ___ # term m of 1 - x + x^2 - ... - -# --- given: exact curve plus four truncations, side by side --- -fig, axes = plt.subplots(1, 2, figsize=(11, 4)) -for ax, (name, exact, term) in zip(axes, [ - (r"$\sin x$", np.sin, sin_term), - (r"$1/(1+x)$", lambda x: 1/(1+x), geo_term)]): - ax.plot(x, exact(x), "k", lw=2, label="exact") - for M in (2, 4, 8, 16): - ax.plot(x, sum(term(m, x) for m in range(M + 1)), lw=1, label=f"M = {M}") - ax.set_ylim(-3, 3); ax.set_xlabel("$x$"); ax.set_title(name) - ax.grid(alpha=0.3); ax.legend(fontsize=8) -plt.tight_layout() -plt.show() - -# --- self-check (leave this alone) --- -_s21 = sum(sin_term(m, x) for m in range(21)) -_g_in = sum(geo_term(m, 0.5) for m in range(40)) -_g_out = sum(geo_term(m, 1.5) for m in range(40)) -fw.check("21 terms reproduce sin(x) on -3 < x < 3", np.max(np.abs(_s21 - np.sin(x))) < 1e-6) -fw.check(f"1/(1+x) converges at x = 0.5 ({_g_in:.4f} vs {1/1.5:.4f})", np.isclose(_g_in, 1/1.5)) -fw.check(f"1/(1+x) diverges at x = 1.5 (partial sum {_g_out:.2e})", abs(_g_out) > 1e3) -``` - -:::{admonition} Solution — Task 2 -:class: dropdown - -```python -import math - -def sin_term(m, x): - return 0.0 if m % 2 == 0 else (-1)**((m-1)//2) * x**m / math.factorial(m) - -def geo_term(m, x): - return (-x)**m -``` -::: - -:::{admonition} Radius of convergence -:class: important - -$\sin x$ improves everywhere as terms are added. $1/(1+x)$ improves only inside $\lvert x\rvert < 1$; outside, each extra term makes the partial sum worse without limit, and at $x = 1.5$ the 40-term partial sum is off by millions. - -The series has a **radius of convergence** of 1, and no amount of computing power extends it. The radius is the distance from the expansion point to the nearest singularity of the function, here from $x=0$ to the pole at $x=-1$. The failure is invisible at $x = 0$ itself, where the function is smooth and the first few terms behave well. Expanding about $x = 1$ instead gives a radius of 2, because the pole is then twice as far away. **The radius is set by where the function is singular, not by its behaviour at the expansion point.** - -Compare Task 1, where more terms always helped and the only question was how many. Here, beyond $\lvert x\rvert = 1$, more terms are useless. Establishing which case applies is a prerequisite to any truncation. -::: - ---- - -## Part 2 — The distance function and its gradient - -All remaining parts use a single cube of sample points. - -```{code-cell} ipython3 -n, L = 61, 2.0 # odd n, so the origin is a sample point -axis = np.linspace(-L, L, n) # one axis, shared by x, y and z -X, Y, Z = np.meshgrid(axis, axis, axis, indexing="ij") -dx = dy = dz = axis[1] - axis[0] - -c = n // 2 # index of the origin -# Mask reused by the self-checks. `interior` drops the two outermost cells, -# so comparisons exclude the six faces of the box, where sampling is worst -# and np.gradient has only one-sided neighbours. -interior = np.zeros(X.shape, dtype=bool) -interior[2:-2, 2:-2, 2:-2] = True - -print(f"grid shape {X.shape}, spacing {dx:.4f} m, {X.size:,} sample points") -print(f"X[i,j,k] = x[i] -> X[-1, 0, 0] = {X[-1, 0, 0]:.1f} m") -``` - -:::{admonition} Grid convention -:class: tip - -**Resolution.** Every derivative on this page is a centred difference, so its error falls as $\Delta x^{2}$. Measured worst-case error against the analytic answer: - -| $n$ | $\Delta x$ [m] | $\lvert\nabla r\rvert$ | $\nabla(1/r)$ | $\nabla\cdot\boldsymbol{E}$ | -| ---: | ---: | ---: | ---: | ---: | -| 21 | 0.200 | 4.1% | 12.5% | 9.1% | -| 41 | 0.100 | 1.8% | 3.3% | 2.4% | -| **61** | **0.067** | **0.8%** | **1.6%** | **1.1%** | -| 81 | 0.050 | 0.5% | 1.0% | 0.6% | - -These are **worst cases** over the region each self-check tests, not averages, and they are what fixes the tolerances. Halving $\Delta x$ reduces the last two columns by close to the factor of four that second-order accuracy predicts (12.5 → 3.3, 9.1 → 2.4). The first column falls by only 2.3. The $|\nabla r|$ error grows towards the source, so the worst sample in the band $0.4 < r < 1.6$ m is whichever one sits nearest the inner edge, and that sample moves when `n` changes. A worst case taken over a boundary that the grid keeps redrawing does not form a smooth sequence. The convergence cell at the end of Part 6 measures a fixed quantity instead and does recover the factor of four. - -$n = 61$ was chosen from this table as the coarsest grid that keeps every task under 2%; each 3-D figure it produces is about 1.5 MB. **If you change `n`, keep it at 41 or above.** The self-checks below allow 5%, and $n = 31$ already fails Task 6 at 6.7%. - -Two properties of this cube matter later. It is a finite window on fields that extend to infinity: the largest closed surface in Part 6 sits only 0.6 m inside the outer face. And $z$ points **up**, as in an ordinary right-handed frame, whereas Part 4 works in the ground, where $z$ points downwards by Earth-science convention. Neither choice is more correct; stating which one is in use is what matters. - -The grid is built with `indexing='ij'`, so axis 0 is $x$, axis 1 is $y$, axis 2 is $z$. - -1. **Derivatives come back in coordinate order:** `np.gradient(f, dx, dy, dz)` returns $\partial f/\partial x$, $\partial f/\partial y$, $\partial f/\partial z$. No transposes. -2. **Always pass the spacings.** Omit them and the derivative is silently wrong by a factor of $1/\Delta x = 15$. - -NumPy's default is `indexing='xy'`, which returns the $y$-derivative first. That single difference accounts for a large share of numerical field bugs. -::: - -The simplest scalar field is the distance to a point: - -$$ r(x,y,z) = \sqrt{(x-x_0)^2 + (y-y_0)^2 + (z-z_0)^2} $$ - -One number at every location in space: no charge, no potential, and no units beyond metres. - -This is the **spherical** radial coordinate $r$, the distance from a point. The cylindrical radius $\varrho$, the distance from an axis, is a different quantity. The equations on this page use $r$, and the code calls it `r`. - -### Task 3 — build the distance field - -**The question:** what do the surfaces of constant $r$ look like, and where do they crowd together? - -The source must be movable: Task 8 places two of them at different points, so write the offsets in now rather than hard-coding the origin. - -```{code-cell} ipython3 -# Task 3 -- distance from a source at (x0, y0, z0) to every point of the grid. - -def distance_to(X, Y, Z, x0=0.0, y0=0.0, z0=0.0): - return ___ # root of the sum of three squares - - -r = ___ # call it: one source, at the origin - -# --- self-check (leave this alone) --- -fw.check_shape("r", r, X.shape) -fw.check("r = 0 at the origin", np.isclose(r[c, c, c], 0.0)) -fw.check("r = 2 m at (2,0,0)", np.isclose(r[-1, c, c], 2.0)) -fw.check("r = 2 m at (0,2,0)", np.isclose(r[c, -1, c], 2.0)) -fw.check("the source can be moved off the origin", - np.isclose(distance_to(X, Y, Z, 1.0, 0.0, 0.0)[c, c, c], 1.0), - "x0, y0, z0 have to appear in the expression -- Task 8 needs them") -``` - -:::{admonition} Solution — Task 3 -:class: dropdown - -```python -def distance_to(X, Y, Z, x0=0.0, y0=0.0, z0=0.0): - return np.sqrt((X - x0)**2 + (Y - y0)**2 + (Z - z0)**2) - - -r = distance_to(X, Y, Z) -``` -::: - -A surface on which $r$ takes one fixed value is an **isosurface**, or level set, the three-dimensional analogue of a contour line on a map. Evenly spaced values of $r$ give evenly spaced shells: the distance function has no preferred radius. - -```{code-cell} ipython3 -fw.show_isosurfaces(X, Y, Z, r, levels=[0.5, 1.0, 1.5], label="r [m]", - title="Isosurfaces of the distance function r") -``` - - -### Task 4 — the gradient of the distance - -Do this one on paper first. Differentiating $r = \sqrt{x^2+y^2+z^2}$ by the chain rule, - -$$ \frac{\partial r}{\partial x} = \frac{x}{r}, \qquad \frac{\partial r}{\partial y} = \frac{y}{r}, \qquad \frac{\partial r}{\partial z} = \frac{z}{r} $$ - -so, collecting the three components, - -$$ \nabla r \;=\; \frac{\partial r}{\partial x}\hat{\boldsymbol{x}} + \frac{\partial r}{\partial y}\hat{\boldsymbol{y}} + \frac{\partial r}{\partial z}\hat{\boldsymbol{z}} \;=\; \frac{x\,\hat{\boldsymbol{x}} + y\,\hat{\boldsymbol{y}} + z\,\hat{\boldsymbol{z}}}{r} \;=\; \hat{\boldsymbol{r}} $$ - -The last step is the definition of the outward unit radial vector: $\hat{\boldsymbol{r}}$ is the position vector divided by its own length. So $\nabla r$ is a **unit** vector pointing **away** from the source, with both direction and magnitude known in advance. - -The cell below tests whether a **finite-difference gradient** on a grid reproduces that. Two measurements: the magnitude, which should be 1, and the projection $\nabla r \cdot \hat{\boldsymbol{r}}$, which recovers the full magnitude only if the gradient is purely radial, with no component along the sphere. - -```{code-cell} ipython3 -# The outward unit radial vector, used again later. -rs = np.maximum(r, 1e-12) # 0/0 at the source is not a lesson -rhx, rhy, rhz = X / rs, Y / rs, Z / rs - -# Task 4 -# 1. grad r, as three components. -# 2. Its magnitude. -# 3. Its projection onto r-hat. -# 4. Draw it, rotate the figure, and compare with the spheres above. - -grx, gry, grz = ___ # all three spacings, in order - -grad_r_mag = ___ # the length of that vector - -radial_part = ___ # its projection onto (rhx, rhy, rhz) - -fw.show_cones(X, Y, Z, grx, gry, grz, step=8, label="|∇r|", unit="-", - title="grad r -- unit vectors pointing away from the source") - -# --- self-check (leave this alone) --- -band = (r > 0.4) & (r < 1.6) -fw.check_shape("grad r (x-component)", grx, X.shape) -fw.check_close("|grad r| = 1 everywhere", grad_r_mag, 1.0, rtol=0.05, where=band) -fw.check_close("grad r is purely radial", radial_part, 1.0, rtol=0.05, where=band) -# The two checks above are the same measurement for THIS field, so they pass -# or fail together. This one is independent: it compares the three components -# against r-hat separately, catching a gradient of the right length but the -# wrong direction. -fw.check(f"grad r = r-hat, componentwise (worst " - f"{np.nanmax(np.abs(np.stack([grx-rhx, gry-rhy, grz-rhz]))[:, band]):.3f} " - f"of a unit vector)", - np.nanmax(np.abs(np.stack([grx - rhx, gry - rhy, grz - rhz]))[:, band]) < 0.05) -``` - -:::{admonition} Solution — Task 4 -:class: dropdown - -```python -grx, gry, grz = np.gradient(r, dx, dy, dz) -grad_r_mag = np.sqrt(grx**2 + gry**2 + grz**2) -radial_part = grx * rhx + gry * rhy + grz * rhz - -print(f"|grad r| median in 0.4 < r < 1.6 m : " - f"{np.median(grad_r_mag[(r > 0.4) & (r < 1.6)]):.4f}") -``` -::: - -:::{admonition} What the algebra means -:class: important - -$\lvert\nabla r\rvert = 1$ needs no calculus: move one metre directly away from the source and the distance to it grows by one metre, so the steepest rate of change of $r$ is 1 m/m everywhere. A gradient carries the direction of steepest increase and a length equal to that rate, here outward and 1. - -The radial check fixes the other half: moving along a sphere does not change $r$, so the gradient has no component there. **$\nabla f$ is normal to the level surfaces of $f$** for every scalar field, not only this one. - -::: - -### Task 5 — the rate of change in an arbitrary direction - -The direction of the gradient is settled: steepest increase, normal to the level surface. Its magnitude is the untested claim. It follows from - -$$ dp = (\nabla p)\cdot d\boldsymbol{l} = \lvert\nabla p\rvert\,\lvert d\boldsymbol{l}\rvert\cos\psi -\qquad\Longrightarrow\qquad -\frac{dp}{dl} = \lvert\nabla p\rvert\cos\psi, $$ - -where $d\boldsymbol{l}$ is a small step in any chosen direction, $dl = \lvert d\boldsymbol{l}\rvert$ is its length, and $\psi$ is the angle between the step and the gradient. The step is written $d\boldsymbol{l}$ rather than $d\boldsymbol{r}$ because $r$ already denotes the distance from the origin on this page. - -Two testable consequences: the rate of change in any direction is $\lvert\nabla p\rvert\cos\psi$, and it never exceeds $\lvert\nabla p\rvert$, which is reached only at $\psi = 0$. - -Measure it. At one point, step a short distance $\varepsilon$ along many unit vectors $\hat{\boldsymbol{u}}$ and compare each measured rate with the prediction. - -```{code-cell} ipython3 -p_field = 1.0 / np.maximum(r, 0.25) # any scalar field will do -gpx, gpy, gpz = np.gradient(p_field, dx, dy, dz) - -ip, jp, kp = 40, 36, 34 # one sample point, off-axis -gvec = np.array([gpx[ip, jp, kp], gpy[ip, jp, kp], gpz[ip, jp, kp]]) -point = np.array([axis[ip], axis[jp], axis[kp]]) - -def p_exact(q): - return 1.0 / np.linalg.norm(q) # the same field, evaluated anywhere - -# Task 5 -- fill in the four blanks; the plotting is given. -grad_mag = ___ # |grad p| at the point, from gvec - -rng = np.random.default_rng(0) -eps = 1e-4 -cosines, rates = [], [] -for _ in range(200): - u = rng.normal(size=3) - u = ___ # make it a UNIT vector - cosines.append(___) # cos(psi) = u . gvec / |grad p| - rates.append(___) # centred difference of p_exact - # along u, step eps, over 2*eps -cosines, rates = np.asarray(cosines), np.asarray(rates) - -# --- given: measurements against the predicted straight line --- -plt.figure(figsize=(5.6, 4.4)) -plt.scatter(cosines, rates, s=12, alpha=0.6, label="measured") -cs = np.linspace(-1, 1, 50) -plt.plot(cs, grad_mag*cs, "k", lw=1.5, label=r"$|\nabla p|\cos\psi$") -plt.xlabel(r"$\cos\psi$") -plt.ylabel(r"$dp/dl$ [m$^{-2}$]") -plt.legend(); plt.grid(alpha=0.3) -plt.show() - -# --- self-check (leave this alone) --- -slope = float(np.polyfit(cosines, rates, 1)[0]) -fw.check_scalar("fitted slope = |grad p|", slope, grad_mag, rtol=0.01) -fw.check("no direction beats |grad p|", np.max(np.abs(rates)) <= grad_mag * 1.001) -``` - -:::{admonition} Solution — Task 5 -:class: dropdown - -```python -grad_mag = float(np.linalg.norm(gvec)) - -# ... and inside the loop: - u = u / np.linalg.norm(u) - cosines.append(float(u @ gvec) / grad_mag) - rates.append((p_exact(point + eps*u) - p_exact(point - eps*u)) / (2*eps)) -``` -::: - -:::{admonition} The magnitude, measured -:class: important - -Every measured rate lies on the line. Three readings of the same figure: - -- **At $\cos\psi = 1$** the step is straight up the gradient and the rate equals $\lvert\nabla p\rvert$. No direction exceeds it, which is the content of *steepest*, now measured rather than asserted. -- **At $\cos\psi = 0$** the step lies in the level surface and $p$ does not change. This is the normality result of Task 4, recovered by a second route. -- **At $\cos\psi = -1$** the rate is $-\lvert\nabla p\rvert$, the steepest descent, which is the direction $\boldsymbol{E} = -\nabla V$ selects in Part 3. - -One vector carries both a direction and a rate; the cosine gives the rate along any other direction. -::: - ---- - -## Part 3 — The inverse distance - -The function that appears in the physics is not the distance but its reciprocal, - -$$ f(r) = \frac{1}{r}, \qquad\text{so}\qquad \nabla f = \frac{d}{dr}\!\left(\frac{1}{r}\right)\hat{\boldsymbol{r}} = -\frac{1}{r^{2}}\,\hat{\boldsymbol{r}} $$ - -The isosurfaces are the same spheres, since $f$ is constant wherever $r$ is constant, but the ordering is inverted: $f$ is largest near the source and decays to zero far away. Predict the effect on the arrows, check the prediction against the formula above, then measure it. - -### Task 6 — the gradient of the inverse distance - -```{code-cell} ipython3 -# The mask keeps the singularity at r = 0 off the grid: everything within -# 0.25 m of the source becomes NaN and is not measured. -r_masked = np.where(r < 0.25, np.nan, r) -f = 1.0 / r_masked - -# Task 6 -- two blanks. Predict the direction before you look at the figure. -fx, fy, fz = ___ # grad f -f_mag = ___ # its magnitude, to compare with 1/r^2 - -# --- given: the numbers, then the picture --- -for rr in (0.6, 1.0, 1.5): - i = int(np.argmin(np.abs(X[:, 0, 0] - rr))) - print(f"r = {rr:.1f} m : |grad f| = {f_mag[i, c, c]:8.4f} 1/r^2 = {1/rr**2:8.4f}") - -# normalise=True draws every arrow the same length, so the figure carries -# direction only. The magnitude moves into the colour, on a log scale, -# because the drawn arrows span a factor of 62. -fw.show_cones(X, Y, Z, fx, fy, fz, step=8, normalise=True, - label="|∇(1/r)|", unit="m-2", - title="grad(1/r) -- pointing back towards the source") - -# --- self-check (leave this alone) --- -outside = (r > 0.5) & interior # `interior` was built in Part 2 -fw.check_close("|grad(1/r)| = 1/r^2", f_mag, 1.0 / r_masked**2, rtol=0.05, where=outside) -fw.check("grad(1/r) points inward at (1,0,0)", fx[-1 - 15, c, c] < 0) -``` - -:::{admonition} Solution — Task 6 -:class: dropdown - -```python -fx, fy, fz = np.gradient(f, dx, dy, dz) -f_mag = np.sqrt(fx**2 + fy**2 + fz**2) -``` -::: - -:::{admonition} The gradient always points towards increase -:class: important - -The arrows have reversed. Same spheres, same source, opposite direction: - -$$ \nabla r = +\hat{\boldsymbol{r}}, \qquad\qquad \nabla\!\left(\frac{1}{r}\right) = -\frac{1}{r^{2}}\,\hat{\boldsymbol{r}} $$ - -Nothing about space changed; what changed is **which way the function climbs**. The steepness changed as well: $1/r$ climbs faster as the source is approached, so its gradient grows as $1/r^2$ instead of staying at 1. - -A gradient encodes nothing about sources, sinks, charges or fields. It encodes only the uphill direction and the rate along it. -::: - -### Task 7 — from geometry to physics - -The physics enters as a single minus sign. The electric potential of a point charge $Q$ is the inverse-distance function with a constant in front, - -$$ V(r) = \frac{1}{4\pi\varepsilon_0}\frac{Q}{r}\quad[\text{V}], $$ - -and the electric field is *defined* as - -$$ \boldsymbol{E} = -\nabla V \quad[\text{V/m}]. $$ - -$\nabla V$ points inward, uphill towards the charge. The minus sign reverses it, so **the field points downhill**, which is the direction a positive test charge released from rest would move, losing potential energy as it goes. - -```{code-cell} ipython3 -V = k_e * Q / r_masked - -# Task 7 -- two blanks. Mind the minus sign. -Ex, Ey, Ez = ___ # E = -grad V -E_mag = ___ - -# --- given: against the analytic k_e*Q/r^2, then the picture --- -for rr in (0.6, 1.0, 1.5): - i = int(np.argmin(np.abs(X[:, 0, 0] - rr))) - print(f"r = {rr:.1f} m : |E| = {E_mag[i, c, c]:8.3f} V/m " - f"analytic = {k_e*Q/rr**2:8.3f} V/m") - -fw.show_cones(X, Y, Z, Ex, Ey, Ez, step=8, normalise=True, - label="|E|", unit="V/m", - title="E = -grad V for a positive point charge") - -# --- self-check (leave this alone) --- -fw.check_close("|E| = Q/(4 pi eps0 r^2)", E_mag, k_e * Q / r_masked**2, - rtol=0.05, where=outside) -fw.check("E points outward at (1,0,0)", Ex[-1 - 15, c, c] > 0) -``` - -:::{admonition} Solution — Task 7 -:class: dropdown - -```python -dVdx, dVdy, dVdz = np.gradient(V, dx, dy, dz) -Ex, Ey, Ez = -dVdx, -dVdy, -dVdz -E_mag = np.sqrt(Ex**2 + Ey**2 + Ez**2) -``` -::: - -:::{admonition} Why the potential is worth defining -:class: tip - -$V$ is a scalar: one number per point, with no direction to track. $\boldsymbol{E}$ is a vector: three numbers. Any operation carried out once on $V$ and then differentiated is cheaper, in arithmetic and in bookkeeping, than the same operation carried out three times on $\boldsymbol{E}$. - -Part 4 is the first case where this matters. -::: - ---- - -## Part 4 — Two sources: superposition - -A single charge is spherically symmetric. Two are not: - -$$ V_{\text{total}} = \frac{1}{4\pi\varepsilon_0}\left(\frac{Q_1}{r_1} + \frac{Q_2}{r_2}\right) $$ - -**Superposition** of potentials is the addition of two numbers at every point, because $V$ is a scalar. Superposing the two fields instead requires a vector sum at every point of the cube. - -Since $\nabla$ is linear, $-\nabla(V_1 + V_2) = \boldsymbol{E}_1 + \boldsymbol{E}_2$ exactly. The efficient route is therefore to **add the potentials and take a single gradient at the end**, with no loss of accuracy. - -### Task 8 — build a dipole - -```{code-cell} ipython3 -# Distances to the two charges. +Q sits at x = +d/2, -Q at x = -d/2, the same -# placement Task 9 gives the current source and sink, so the two figures can -# be compared directly. The guard trips only if a grid point lands exactly on -# a charge; at n = 61 none does, so nothing is masked and the full field is -# shown. Raise it if you change the grid. -d_sep = 1.0 # charge separation [m] -r_plus = np.where(distance_to(X, Y, Z, +d_sep/2, 0.0, 0.0) < 0.01, np.nan, - distance_to(X, Y, Z, +d_sep/2, 0.0, 0.0)) -r_minus = np.where(distance_to(X, Y, Z, -d_sep/2, 0.0, 0.0) < 0.01, np.nan, - distance_to(X, Y, Z, -d_sep/2, 0.0, 0.0)) - -# Task 8 -- two blanks. -V_dip = ___ # superpose: +Q over r_plus, -Q over r_minus -Ex_d, Ey_d, Ez_d = ___ # ONE gradient of the sum, negated - -# --- given: the z = 0 plane, potential as colour, field as streamlines --- -fw.show_field_slice(X, Y, Z, Ex_d, Ey_d, background=V_dip, - title="Source and sink: potential (colour) and field lines", - label="$V$ [V]") -plt.show() - -# --- self-check (leave this alone) --- -mid = np.abs(X) < 1e-9 # the plane x = 0, halfway between them -fw.check_shape("V_dip", V_dip, X.shape) -fw.check("V = 0 on the mid-plane", - np.nanmax(np.abs(V_dip[mid])) < 1e-6 * np.nanmax(np.abs(V_dip))) -fw.check("E on the mid-plane points from + to -", np.nanmean(Ex_d[mid]) < 0) -``` - -:::{admonition} Solution — Task 8 -:class: dropdown - -```python -V_dip = k_e * Q / r_plus + k_e * (-Q) / r_minus - -dVx, dVy, dVz = np.gradient(V_dip, dx, dy, dz) -Ex_d, Ey_d, Ez_d = -dVx, -dVy, -dVz -``` -::: - -:::{admonition} The mid-plane -:class: tip - -At $x = 0$ the potential is **exactly zero**, while the field is at its strongest, pointing straight from the positive charge to the negative one, here along $-\hat{\boldsymbol{x}}$ because $+Q$ sits on the right. - -The field is the slope of the potential, not its value: terrain at sea level can still be steep. The figure also shows the streamlines crossing the coloured contours at right angles everywhere, which is the normality result of Task 4 appearing in a field that was not constructed radially. -::: - -### The far field of the dipole - -$V_{\text{dip}}$ is not a series; it is two exact terms. Viewed from far enough away, however, the two charges are no longer resolvable, and what survives is a **truncation**. - -Expand $1/r_\pm$ in powers of $d/r$ and add. The leading terms are equal and opposite, since the pair carries no net charge, and the first surviving term is - -$$ V \;\approx\; \frac{1}{4\pi\varepsilon_0}\frac{\boldsymbol{p}\cdot\hat{\boldsymbol{r}}}{r^{2}}, \qquad \boldsymbol{p} = Q d\,\hat{\boldsymbol{x}}, $$ - -with the **dipole moment** $\boldsymbol{p}$ pointing from the negative charge to the positive one. Every discarded term is smaller by a further factor of $(d/r)^2$. This is the question of Task 1 asked of distance rather than of term count: at what range is one term enough? - -```{code-cell} ipython3 -# --- given: exact against the one-term far field, along the +x axis --- -p_mom = Q * d_sep # dipole moment [C m] -r_ff = np.logspace(np.log10(0.8), np.log10(60), 2000) -V_ex = k_e * Q * (1/np.abs(r_ff - d_sep/2) - 1/np.abs(r_ff + d_sep/2)) -V_ff = k_e * p_mom / r_ff**2 # p . r-hat = p on the axis -err_ff = np.abs(V_ff - V_ex) / np.abs(V_ex) - -plt.figure(figsize=(5.8, 4.2)) -plt.loglog(r_ff / d_sep, err_ff, "k", lw=1.6) -for tol, colour in ((0.10, "C1"), (0.01, "C2"), (0.001, "C3")): - r_ok = r_ff[np.argmax(err_ff < tol)] / d_sep - plt.axhline(tol, color=colour, lw=0.8, ls=":") - plt.plot([r_ok], [tol], "o", color=colour, ms=5) - print(f" one term is good to {tol:6.1%} beyond r = {r_ok:5.1f} separations") -plt.xlabel("$r$ / separation $d$"); plt.ylabel("relative error of the one-term form") -plt.grid(alpha=0.3, which="both"); plt.title("How far is far?") -plt.show() - -# --- self-check (leave this alone) --- -fw.check("the far-field error falls as (d/r)^2", - np.isclose(np.polyfit(np.log(r_ff[r_ff > 10]), np.log(err_ff[r_ff > 10]), 1)[0], - -2.0, atol=0.05)) -``` - -:::{admonition} The same question as the bouncing ball -:class: important - -Two decades of accuracy cost a factor of ten in distance: 10% at $1.6\,d$, 1% at $5\,d$, 0.1% at $16\,d$. This is the $(d/r)^2$ law, and the factor between successive rows is $\sqrt{10}\approx 3.2$. - -Compare Task 1, where 1% accuracy required 88 terms, and the count grew as the ball became more elastic. Here the controlling variable is a distance rather than a term count, and the requirement grows the closer the observation point. In both cases the truncation is only as good as the regime, and in both cases the regime can be established by measurement. - -This single term is why a compass works. A magnet has a complicated field close up; at a metre it is a dipole and nothing else, which is why the Earth's field is written as the single term used in Task 11. -::: - -The same object in three dimensions, with positive and negative equipotential surfaces drawn transparent: - -```{code-cell} ipython3 -lobe = np.nanpercentile(np.abs(V_dip), 97) -fw.show_isosurfaces(X, Y, Z, np.nan_to_num(V_dip), levels=[-lobe, -lobe/3, lobe/3, lobe], - colorscale="RdBu", reversescale=True, opacity=0.3, label="V [V]", - title="Equipotential surfaces of a dipole") -``` - -### Task 9 — the same mathematics as a geophysical survey - -Task 8 was two charges in vacuum. The mathematics below is identical; the physics is not. - -Drive a current $I$ into the ground through one electrode and extract it through another, a distance $a$ away. Air does not conduct, so in ground of resistivity $\rho$ the current spreads through the **lower half-space only**, and each electrode contributes $\rho I/2\pi r$ rather than $\rho I / 4\pi r$. Superposition gives - -$$ V(x,y,z) = \frac{\rho I}{2\pi}\left(\frac{1}{\lvert\boldsymbol{r}-\boldsymbol{a}/2\rvert} - \frac{1}{\lvert\boldsymbol{r}+\boldsymbol{a}/2\rvert}\right), \qquad z \ge 0 \ \text{(down into the ground)}. $$ - -The field follows as before, $\boldsymbol{E} = -\nabla V$, and Ohm's law in local form turns it into a **current density**: - -$$ \boldsymbol{J} = \rho^{-1}\boldsymbol{E} = -\rho^{-1}\nabla V \quad [\text{A}/\text{m}^2]. $$ - -This is a DC resistivity survey, a standard near-surface geophysical measurement. Map it two ways: on the ground surface, where the electrodes are planted, and on a vertical section cut between them. - -:::{admonition} $\rho$ means something else here -:class: warning - -In this task $\rho$ is the **electrical resistivity** in Ω·m. In Task 13 it is a charge density in C/m³, written $\rho_v$ to keep the two apart. The symbol is overloaded throughout the subject; the units identify which is meant. -::: - -The ground is a half-space, so this task needs its own grid: $x$ and $y$ still run from $-L$ to $L$, but $z$ runs from $0$ at the surface **downwards**, following the Earth-science convention. - -A real electrode is a metal stake, not a mathematical point: a conductor of finite radius $r_{\text{el}}$ held at one potential over its whole surface. Flooring the distance at $r_{\text{el}}$ models it that way and keeps $1/r$ bounded. Nothing is masked, no sample is discarded, and every derivative below acts on a field that is finite everywhere. - -```{code-cell} ipython3 -rho, I, a_sep = 100.0, 1.0, 1.0 # ohm.m, ampere, electrode spacing [m] -r_el = 0.12 # electrode radius [m] - -axis_g = np.linspace(-2.0, 2.0, 81) # x and y, across the survey line -depth = np.linspace(0.0, 2.0, 51) # z, down into the ground -Xg, Yg, Zg = np.meshgrid(axis_g, axis_g, depth, indexing="ij") -dxg = axis_g[1] - axis_g[0] -dzg = depth[1] - depth[0] -print(f"dxg = {dxg:.3f} m, dzg = {dzg:.3f} m <- deliberately not equal") - -def dist_to(x0): - """Distance to an electrode at (x0, 0, 0), floored at its own radius.""" - return np.maximum(np.sqrt((Xg - x0)**2 + Yg**2 + Zg**2), r_el) - -# Task 9 -- two blanks. This is Task 8 again, in different clothes. -# V: the formula above, source at x = +a_sep/2, sink at x = -a_sep/2. -# dist_to floors the distance at the electrode radius, so there is -# nothing to mask and nothing to nan_to_num. -# J: -grad(V)/rho. Pass dxg, dxg, dzg. On this grid z is spaced -# differently from x and y, and passing dxg three times costs 6.5% on -# the current measured in the next cell, enough to fail its check. - -V_dc = ___ -Jx, Jy, Jz = ___ - -# --- given: the survey, both panels on one colour scale and one colorbar --- -# plane="z" is the ground surface; plane="y" is the vertical section, where -# the in-plane components are (Jx, Jz), not (Jx, Jy). -vm = float(np.nanpercentile(np.abs(V_dc[:, :, 0]), 98)) -fig, axes = plt.subplots(2, 1, figsize=(7.2, 9.2)) -for ax_, comps, pl, ttl in ((axes[0], (Jx, Jy), "z", "a) ground surface, $z=0$"), - (axes[1], (Jx, Jz), "y", "b) vertical section, $y=0$")): - _, cf = fw.show_field_slice(Xg, Yg, Zg, *comps, background=V_dc, ax=ax_, - plane=pl, vmin=-vm, vmax=vm, colorbar=False, - density=1.2, title=ttl) -axes[1].invert_yaxis() # depth increases downwards -fig.colorbar(cf, ax=axes, label="$V$ [V]", fraction=0.05, pad=0.03) -plt.show() - -# --- self-check (leave this alone) --- -mid_dc = np.abs(Xg) < 1e-9 -fw.check("V is finite everywhere -- no holes in the model", - np.all(np.isfinite(V_dc)) and np.all(np.isfinite(Jx))) -fw.check("V = 0 on the mid-plane between the electrodes", - np.nanmax(np.abs(V_dc[mid_dc])) < 1e-6 * np.nanmax(np.abs(V_dc))) -fw.check("current flows from the source towards the sink at the surface", - np.nanmean(Jx[mid_dc]) < 0) -``` - -:::{admonition} Solution — Task 9 -:class: dropdown - -```python -V_dc = rho * I / (2*np.pi) * (1/dist_to(+a_sep/2) - 1/dist_to(-a_sep/2)) - -gVx, gVy, gVz = np.gradient(V_dc, dxg, dxg, dzg) -Jx, Jy, Jz = -gVx/rho, -gVy/rho, -gVz/rho -``` - -A presentation point worth reusing: `show_field_slice` returns `(ax, cf)`, so passing `colorbar=False` on both panels and handing the mappable `cf` to `fig.colorbar(..., ax=axes)` draws **one** bar beside the pair. Two bars carrying identical numbers are clutter, and they suggest to the reader that the scales differ. -::: - -Now use the field as an instrument. All the current injected at one electrode must cross any closed surface drawn around it, since there is nowhere else for it to go. Test that. - -```{code-cell} ipython3 -# The five faces of a box buried in the ground around one electrode. The top -# face is deliberately absent: it lies in the surface z = 0, where no current -# crosses into the air, so its contribution is zero by physics. -def buried_box_current(xc, hw=0.3): - i0 = int(np.argmin(np.abs(axis_g - (xc - hw)))) - i1 = int(np.argmin(np.abs(axis_g - (xc + hw)))) - j0 = int(np.argmin(np.abs(axis_g + hw))) - j1 = int(np.argmin(np.abs(axis_g - hw))) - k1 = int(np.argmin(np.abs(depth - hw))) - sx, sy, sz = slice(i0, i1+1), slice(j0, j1+1), slice(0, k1+1) - return (fw.area_integral(Jx[i1, sy, sz], dxg, dzg) - fw.area_integral(Jx[i0, sy, sz], dxg, dzg) - + fw.area_integral(Jy[sx, j1, sz], dxg, dzg) - fw.area_integral(Jy[sx, j0, sz], dxg, dzg) - + fw.area_integral(Jz[sx, sy, k1], dxg, dxg)) - -for xc, name in ((+a_sep/2, "source"), (-a_sep/2, "sink")): - print(f"current out of a box around the {name:6s}: {buried_box_current(xc):+7.4f} A") -print(f" injected: {I:+7.4f} A") - -# --- self-check (leave this alone) --- -fw.check_scalar("box around the source carries I", buried_box_current(+a_sep/2), I, rtol=0.01, unit=" A") -fw.check_scalar("box around the sink carries -I", buried_box_current(-a_sep/2), -I, rtol=0.01, unit=" A") -``` - -:::{admonition} Why five faces and not six? -:class: important - -The box is closed by the ground surface itself. Air does not conduct, so $J_z = 0$ at $z=0$. This is a **boundary condition**, true by physics, and not a quantity to be measured. - -Measuring it anyway is instructive. `np.gradient` has no neighbour above $z=0$, so it falls back to a one-sided difference and reports a spurious $J_z$ averaging $+0.25$ A/m² over the top of the box, apparently current entering from the air. The outward normal on that face is $-\hat{\boldsymbol{z}}$, so the face enters the sum as $-0.088$ A and reduces the box total from $1.003$ A to $0.915$ A, an **8.5% error** on a result that is otherwise accurate to 0.3%. - -The rule generalises well beyond this lab: **impose a boundary condition you know exactly, rather than asking a finite-difference stencil to recover it.** Numerical derivatives are least reliable where the domain stops. -::: - ---- - -:::{admonition} End of session 1 -:class: note - -Parts 1–4 cover the gradient and close the first session. **Part 5 onwards requires the divergence**, which is lectured next. Return to it in the following session, or read ahead. -::: - ---- - -## Part 5 — Divergence - -The gradient takes a scalar and returns a vector. The divergence takes a vector field and returns a scalar: - -$$ \nabla\cdot\boldsymbol{A} \;=\; \lim_{\Delta V \to 0}\frac{1}{\Delta V}\oint_S \boldsymbol{A}\cdot\hat{\boldsymbol{n}}\,dS \;=\; \frac{\partial A_x}{\partial x} + \frac{\partial A_y}{\partial y} + \frac{\partial A_z}{\partial z} $$ - -Read the definition on the left rather than the formula on the right: **treat $\boldsymbol{A}$ as a fluid velocity**, place a small box anywhere, and measure the net outflow through its walls per unit volume. - -| $\nabla\cdot\boldsymbol{A}$ | Name | Picture | -| :---: | :--- | :--- | -| $> 0$ | **source** | a tap: more leaves than arrives | -| $< 0$ | **sink** | a drain: more arrives than leaves | -| $= 0$ | **solenoidal** | whatever flows in, flows out | - -### Task 10 — the operator, and its independence of the origin - -The operator is three lines, and they are given. One derivative along one axis per component: `np.gradient(Ax, dx, axis=0)` returns $\partial A_x/\partial x$ and nothing else, whereas asking for all three and discarding two costs three times the memory. The cross terms are not part of a divergence. - -**The question is the one raised by the definition.** Flux per unit volume is measured around a point, so does the result depend on which point is called the origin? Take the outward flow $\boldsymbol{A} = \boldsymbol{r}$, whose divergence follows on paper as $1+1+1 = 3$, then shift the whole field so that it streams out of $(0.8, -0.4, 0.3)$. Predict the divergence before computing it. - -```{code-cell} ipython3 -# --- given --- -def divergence(Ax, Ay, Az, dx, dy, dz): - return (np.gradient(Ax, dx, axis=0) - + np.gradient(Ay, dy, axis=1) - + np.gradient(Az, dz, axis=2)) - -# Task 10 -- two blanks. The same outward flow, seen from somewhere else. -x0, y0, z0 = 0.8, -0.4, 0.3 -Sx, Sy, Sz = ___ # the field r - r0, as three arrays -div_shifted = ___ # its divergence - -# --- self-check (leave this alone) --- -fw.check_close("div of the position vector = 3", - divergence(X, Y, Z, dx, dy, dz), 3.0, rtol=1e-6) -fw.check_close("...and 3 again when the source is moved", - div_shifted, 3.0, rtol=1e-6) -fw.check("the shifted field really is different from the original", - not np.allclose(Sx, X)) -``` - -:::{admonition} Solution — Task 10 -:class: dropdown - -```python -Sx, Sy, Sz = X - x0, Y - y0, Z - z0 -div_shifted = divergence(Sx, Sy, Sz, dx, dy, dz) -``` -::: - -:::{admonition} Why the answer had to be 3 either way -:class: tip - -Moving the source changed every arrow in the box and changed the divergence nowhere. Differentiation removes the constant: $\partial(x - x_0)/\partial x = 1$ for any $x_0$. - -The divergence is a **local** quantity: it is built from a limit taken around one point, so it depends on the field in a shrinking neighbourhood of that point and not on where the axes were placed. Every operator in this course has that property, and it is what makes $\nabla\cdot\boldsymbol{E} = \rho_v/\varepsilon_0$ a statement about places rather than about coordinate systems. -::: - -### Task 11 — the only incompressible radial flow - -Water of constant density flows outward from a source at the origin. Away from that source nothing is created or destroyed, so the flow is **incompressible**: - -$$ \nabla\cdot\boldsymbol{v} = 0 \qquad \text{for } r \neq 0. $$ - -Constant density and a point source force the flow to be radial, $\boldsymbol{v} = f(r)\,\boldsymbol{r}$, and incompressibility then pins $f$ down completely: - -$$ \nabla\cdot\boldsymbol{v} = 3f(r) + r\frac{df}{dr} = 0 \qquad\Longrightarrow\qquad f(r) = \frac{A}{r^{3}}. $$ - -Rather than assume this, test four candidates and let the divergence select. - -```{code-cell} ipython3 -# The measure reported by the loop below: -# -# |div v| / (|v| / r), median over the test band -# -# |v|/r is the natural size of a derivative of v, so the ratio is a pure -# number: 1 means "as large as a derivative of this field could be". - -r_safe = np.where(r < 0.3, np.nan, r) -band_i = interior & (r > 0.6) & (r < 1.6) - -# Task 11 -- three blanks, inside the loop. -results = {} -for name, f_r in [("const", np.ones_like(r_safe)), - ("1/r^2", 1/r_safe**2), - ("1/r^3", 1/r_safe**3), - ("1/r^4", 1/r_safe**4)]: - vx, vy, vz = ___ # v = f(r) * (X, Y, Z): three arrays - dv = ___ # its divergence (nan_to_num each part) - scale = ___ # |v|/r AT THE BAND POINTS -- index it - # with [band_i], so it comes out 1-D - # and the same length as dv[band_i] - - # --- given --- - results[name] = np.nanmedian(np.abs(dv[band_i]) / scale) - print(f" f = {name:6s}: median |div v| / (|v|/r) = {results[name]:8.2%}") - -# --- self-check (leave this alone) --- -fw.check(f"scale is one value per band point ({np.shape(scale)} vs " - f"{np.shape(dv[band_i])})", np.shape(scale) == np.shape(dv[band_i]), - "index it with [band_i] -- a whole-grid array or a single median " - "both change the statistic being reported") -fw.check(f"1/r^3 is the divergence-free one ({results['1/r^3']:.2%})", - results["1/r^3"] < 0.05) -fw.check("...and the other three are not", - min(results[k] for k in ("const", "1/r^2", "1/r^4")) > 0.5) -fw.check(f"f = const reproduces Task 10's div(r) = 3 ({results['const']:.2%})", - np.isclose(results["const"], 3.0, rtol=1e-3)) -``` - -:::{admonition} Solution — Task 11 -:class: dropdown - -```python - vx, vy, vz = f_r*X, f_r*Y, f_r*Z - dv = divergence(*(np.nan_to_num(q) for q in (vx, vy, vz)), dx, dy, dz) - scale = (np.sqrt(vx**2 + vy**2 + vz**2) / r_safe)[band_i] -``` -::: - -:::{admonition} Where the inverse-square law comes from -:class: important - -One candidate gives 300%, two give almost exactly 100%, and one gives 0.66%. Only $f = A/r^{3}$ survives, as the algebra predicts. - -The 300% is not an accident. For $f = \text{const}$ the field is the position vector, $\boldsymbol{v} = \boldsymbol{r}$, whose divergence Task 10 measured as exactly 3, while $\lvert\boldsymbol{v}\rvert/r = 1$, so the ratio must be 3. The surviving case rewrites as - -$$ \boldsymbol{v} = \frac{A}{r^{3}}\boldsymbol{r} = \frac{A}{r^{2}}\,\hat{\boldsymbol{r}}. $$ - -**This is the same $1/r^{2}$ used since Task 6.** Here it was not assumed and no charge was mentioned; it follows from conservation away from the source together with the three-dimensionality of space. The surface of a sphere grows as $r^{2}$, so a fixed flux crossing it must thin as $1/r^{2}$. - -Coulomb's law, Newtonian gravity and this flow share an exponent for that one geometric reason. -::: - -### Task 11, continued — a field with no source anywhere - -Note the restriction on that result: $\nabla\cdot\boldsymbol{v} = 0$ **for $r \neq 0$**. The origin must be excluded, because that is where the water is injected; a closed surface around it would find the tap. - -The next field admits no such exception. To first order the Earth's magnetic field is a **dipole**: a north and a south pole so close together that they coincide. With dipole moment $\boldsymbol{m}$, - -$$ \boldsymbol{B} = \frac{3\boldsymbol{r}\,(\boldsymbol{r}\cdot\boldsymbol{m}) - r^{2}\boldsymbol{m}}{r^{5}}. $$ - -Take $\boldsymbol{m} = \hat{\boldsymbol{z}}$ on the cube of Part 2, where $z$ points up, and measure the divergence with the same function. - -The Earth's own moment points roughly geographic south, which is why the magnetic pole in the Arctic is magnetically a **south** pole and attracts the north end of a compass needle. Reversing $\boldsymbol{m}$ reverses every arrow below and leaves $\nabla\cdot\boldsymbol{B}$ unchanged. - -```{code-cell} ipython3 -# Task 11, continued -- fill in the three components. -# With m = z-hat, the dot product r . m is simply Z. -# Careful with the second term: it appears only in the z-component. - -r_dot_m = Z -Bx = ___ -By = ___ -Bz = ___ - -div_B = divergence(np.nan_to_num(Bx), np.nan_to_num(By), np.nan_to_num(Bz), dx, dy, dz) - -# --- given: the same scale-free measure as above --- -B_mag = np.sqrt(Bx**2 + By**2 + Bz**2) -print(f" dipole B : median |div B| / (|B|/r) = " - f"{np.nanmedian(np.abs(div_B[band_i]) / (B_mag/r_safe)[band_i]):8.2%}") - -# --- self-check (leave this alone) --- -fw.check("B is divergence-free", - np.nanmedian(np.abs(div_B[band_i]) / (B_mag/r_safe)[band_i]) < 0.05) -fw.check("B is not simply radial (it has a north and a south)", - np.nanmin((Bx*X + By*Y + Bz*Z)[band_i]) < 0) -``` - -:::{admonition} Solution — Task 11, continued -:class: dropdown - -```python -Bx = 3*X*r_dot_m / r_safe**5 -By = 3*Y*r_dot_m / r_safe**5 -Bz = (3*Z*r_dot_m - r_safe**2) / r_safe**5 -``` -::: - -:::{admonition} No magnetic monopoles -:class: important - -Both fields are divergence-free over the region measured, but the two statements differ. - -The flow required an exclusion: $\nabla\cdot\boldsymbol{v} = 0$ away from the origin, because the origin is a tap. The dipole requires none, and $\nabla\cdot\boldsymbol{B} = 0$ holds **everywhere in space, including at the source**. No point can be excluded to reveal a magnet leaking field the way the tap leaks water. This is one of Maxwell's equations: magnetic monopoles do not exist, and field lines of $\boldsymbol{B}$ never begin or end but close on themselves. - -Two remarks on the numbers. Both cells report the same scale-free measure, so the results are directly comparable. The dipole's 1.8% is worse than the radial flow's 0.66%, not because the physics is less secure but because $\boldsymbol{B}$ falls off as $1/r^{3}$ rather than $1/r^{2}$, leaving a centred difference more curvature to miss. Part 6 tests the same claim far below 2% by putting a closed surface around the dipole instead of differentiating it. - -The second check is also informative: $\boldsymbol{B}\cdot\boldsymbol{r}$ is negative somewhere, whereas the outward flow of Task 11 is never negative. The dipole points inward over part of space; it returns. That is the numerical signature of a field closing on itself. -::: - -### Task 12 — three flows - -Three velocity fields. For each one: **sketch it, predict the sign of the divergence, then measure.** Record the predictions first; the task is about the gap between intuition and the result. - -| | Field $\boldsymbol{A}$ | What it looks like | -| :---: | :--- | :--- | -| **(a)** | $x\,\hat{\boldsymbol{x}} + y\,\hat{\boldsymbol{y}} + z\,\hat{\boldsymbol{z}}$ | outward flow in all directions | -| **(b)** | $-y\,\hat{\boldsymbol{x}} + x\,\hat{\boldsymbol{y}}$ | fluid rotating about the $z$-axis | -| **(c)** | $x\,\hat{\boldsymbol{x}} - y\,\hat{\boldsymbol{y}}$ | stretching along $x$, squeezing along $y$ | - -```{code-cell} ipython3 -# Record the predictions BEFORE running the next cell: +1 for a source, -# -1 for a sink, 0 for solenoidal. The next cell scores them. -predictions = {"a": ___, "b": ___, "c": ___} -``` - -```{code-cell} ipython3 -# Task 12 -- six blanks: three fields, three divergences. -zero = np.zeros_like(X) -Aa = ___ # (a) outward flow, as a triple -Ab = ___ # (b) rotation about z -Ac = ___ # (c) stretch in x, squeeze in y - -div_a = ___ -div_b = ___ -div_c = ___ - -# --- given: the three side by side, one shared scale, one colorbar --- -for name, d in [("(a) outward flow", div_a), ("(b) rotation", div_b), - ("(c) shear", div_c)]: - print(f"{name:20s} div = {d.mean():+.3f}") - -fig, axes = plt.subplots(1, 3, figsize=(16, 4.6)) -for ax_, (name, A, d) in zip(axes, [("(a) outward flow", Aa, div_a), - ("(b) rotation", Ab, div_b), - ("(c) shear flow", Ac, div_c)]): - fw.show_field_slice(X, Y, Z, *A[:2], background=d, ax=ax_, density=1.1, - vmin=-3, vmax=3, colorbar=(ax_ is axes[-1]), - label=r"$\nabla\cdot\boldsymbol{A}$ [s$^{-1}$]", title=name) -plt.tight_layout() -plt.show() -# Examine (b) and (c) before reading the note below: both come out a uniform -# zero, for entirely different reasons. - -# --- self-check (leave this alone) --- -# (a) has a non-zero answer, so a relative test works. (b) and (c) are exactly -# zero, and nothing can be measured relative to zero, so they get an absolute -# tolerance instead. -fw.check_close("(a) div = 3", div_a, 3.0, rtol=1e-6) -fw.check_abs("(b) div = 0 (rotation)", div_b, atol=1e-9) -fw.check_abs("(c) div = 0 (shear)", div_c, atol=1e-9) - -for key, measured in (("a", div_a), ("b", div_b), ("c", div_c)): - sign = int(np.sign(np.round(measured.mean(), 6))) - verdict = "as predicted" if predictions[key] == sign else "NOT what you predicted" - print(f" ({key}) you said {predictions[key]:+d}, measured {sign:+d} -- {verdict}") -``` - -:::{admonition} Solution — Task 12 -:class: dropdown - -```python -Aa = (X, Y, Z) -Ab = (-Y, X, zero) -Ac = (X, -Y, zero) - -div_a = divergence(*Aa, dx, dy, dz) -div_b = divergence(*Ab, dx, dy, dz) -div_c = divergence(*Ac, dx, dy, dz) -``` -::: - -:::{admonition} Field (c) is the trap -:class: warning - -Along the $x$-axis, field (c) flows outward and resembles a source. It is not: - -$$ \nabla\cdot\boldsymbol{A} = \frac{\partial}{\partial x}(x) + \frac{\partial}{\partial y}(-y) = 1 - 1 = 0 $$ - -Place a box at the origin: fluid leaves through the left and right walls and enters through the top and bottom at exactly the same rate. The parcel changes **shape**, not **volume**. - -Diverging arrows are not divergence. Outflow in one direction can be cancelled exactly by inflow in another. Task 14 puts a closed surface around this field and measures the cancellation directly. -::: - -### Task 13 — the divergence as a charge detector - -Gauss's law, for a field in vacuum, says - -$$ \nabla\cdot\boldsymbol{E} = \frac{\rho_v}{\varepsilon_0} $$ - -which is a strong claim: **the divergence of $\boldsymbol{E}$ at a point gives the charge density at that point and nothing else.** Where there is no charge, $\boldsymbol{E}$ is solenoidal, however widely its arrows spread. - -Test that pointwise, on a source a grid can hold. A point charge cannot serve: it has infinite density at one location. Take instead a charge **distributed over a finite blob**, which is what any real charged object is: - -$$ \rho_v(r) = \rho_{v0}\,e^{-r^{2}/a^{2}}, \qquad \rho_{v0} = 10^{-9}\ \text{C/m}^3, \qquad a = 0.5\ \text{m} $$ - -Here $a$ is the **width of the blob**. In Task 9 the same letter denoted an electrode separation, the second overloaded symbol on this page after $\rho$. The code keeps them apart as `a` and `a_sep`; in algebra only the context distinguishes them. - -Integrating over a sphere of radius $r$ gives the charge it encloses: - -$$ Q_{\text{enc}}(r) = \int_0^{r}\!\rho_v\,4\pi r'^{2}\,dr' = 4\pi\rho_{v0}\left[\frac{a^{3}\sqrt{\pi}}{4}\operatorname{erf}\!\left(\frac{r}{a}\right) - \frac{a^{2}r}{2}e^{-r^{2}/a^{2}}\right] $$ - -and Gauss's law, $E_r = Q_{\text{enc}}/4\pi\varepsilon_0r^{2}$, then gives the field, with the $4\pi$ cancelling: - -$$ E_r(r) = \frac{\rho_{v0}}{\varepsilon_0 r^{2}}\left[\frac{a^{3}\sqrt{\pi}}{4}\operatorname{erf}\!\left(\frac{r}{a}\right) - \frac{a^{2}r}{2}e^{-r^{2}/a^{2}}\right] $$ - -One check: near the centre $Q_{\text{enc}}$ grows as $r^{3}$ while the surface grows as $r^{2}$, so $E_r \to \rho_{v0} r/3\varepsilon_0$, zero at the centre, rising linearly, and peaking at $r \approx a$. - -```{code-cell} ipython3 -from scipy.special import erf - -a, rho_v0 = 0.5, 1e-9 - -# --- given: the charge density, and the field Gauss's law gives it --- -# The two bracketed terms nearly cancel for r << a, so the closed form loses -# accuracy below r ~ 1e-6 m. On this grid the only such sample is the origin, -# where the r-hat components are zero in any case. -rho_v = rho_v0 * np.exp(-r**2 / a**2) -E_r = rho_v0 / (epsilon_0 * rs**2) * ( - (a**3 * np.sqrt(np.pi) / 4) * erf(rs / a) - (a**2 * rs / 2) * np.exp(-rs**2 / a**2) -) - -# Task 13 -- two blanks. -# E_r is a radial MAGNITUDE. Give it a direction, then differentiate. -Ex_b, Ey_b, Ez_b = ___ # components along (rhx, rhy, rhz) -div_blob = ___ # your Task 10 operator - -# --- given: the two pictures, forced onto one scale so they are comparable --- -hi = float(np.nanmax(rho_v / epsilon_0)) -units = r"[V m$^{-2}$]" -fig, axes = plt.subplots(1, 2, figsize=(12, 4.4)) -fw.show_scalar_slice(X, Y, Z, div_blob, ax=axes[0], cmap="magma", label=units, - vmin=0, vmax=hi, title=r"measured $\nabla\cdot\boldsymbol{E}$") -fw.show_scalar_slice(X, Y, Z, rho_v / epsilon_0, ax=axes[1], cmap="magma", label=units, - vmin=0, vmax=hi, title=r"actual $\rho_v/\varepsilon_0$") -plt.tight_layout() -plt.show() - -print(f"peak of rho_v/eps0 : {np.nanmax(rho_v/epsilon_0):8.2f}") -print(f"peak of measured div: {np.nanmax(div_blob):8.2f}") - -# --- self-check (leave this alone) --- -peak = np.nanmax(rho_v / epsilon_0) -_e = np.abs(div_blob[interior] - (rho_v / epsilon_0)[interior]) / peak -cart_worst, cart_median = float(_e.max()), float(np.median(_e)) -fw.check(f"div E = rho_v/eps0 pointwise (worst {cart_worst:.2%} of peak)", - cart_worst < 0.05, "check the component construction Ex_b = E_r * rhx") -``` - -:::{admonition} Solution — Task 13 -:class: dropdown - -```python -Ex_b, Ey_b, Ez_b = E_r * rhx, E_r * rhy, E_r * rhz -div_blob = divergence(Ex_b, Ey_b, Ez_b, dx, dy, dz) -``` -::: - -:::{admonition} What the two panels show -:class: important - -The two panels show the same distribution. The location of the charge was never supplied to the code: a field was differentiated, and the charge distribution came back out. - -Note where the divergence vanishes: everywhere outside the blob, where the field is still large and still spreading. **Strong field, zero divergence**: the two quantities are unrelated. -::: - -### The same operator, a different formula - -Everything so far used the Cartesian formula, because `np.gradient` differentiates along array axes. The divergence is flux per unit volume, a physical quantity that cannot depend on the choice of axes. Only the formula changes: - -| | Gradient $\nabla T$ | Divergence $\nabla\cdot\boldsymbol{A}$ | -| :--- | :--- | :--- | -| Cartesian $(x,y,z)$ | $\dfrac{\partial T}{\partial x}\hat{\boldsymbol{x}} + \dfrac{\partial T}{\partial y}\hat{\boldsymbol{y}} + \dfrac{\partial T}{\partial z}\hat{\boldsymbol{z}}$ | $\dfrac{\partial A_x}{\partial x} + \dfrac{\partial A_y}{\partial y} + \dfrac{\partial A_z}{\partial z}$ | -| Cylindrical $(\varrho,\phi,z)$ | $\dfrac{\partial T}{\partial \varrho}\hat{\boldsymbol{\varrho}} + \dfrac{1}{\varrho}\dfrac{\partial T}{\partial \phi}\hat{\boldsymbol{\phi}} + \dfrac{\partial T}{\partial z}\hat{\boldsymbol{z}}$ | $\dfrac{1}{\varrho}\dfrac{\partial (\varrho v_\varrho)}{\partial \varrho} + \dfrac{1}{\varrho}\dfrac{\partial v_\phi}{\partial \phi} + \dfrac{\partial v_z}{\partial z}$ | -| Spherical $(r,\phi,\theta)$ | $\dfrac{\partial T}{\partial r}\hat{\boldsymbol{r}} + \dfrac{1}{r}\dfrac{\partial T}{\partial \theta}\hat{\boldsymbol{\theta}} + \dfrac{1}{r\sin\theta}\dfrac{\partial T}{\partial \phi}\hat{\boldsymbol{\phi}}$ | $\dfrac{1}{r^{2}}\dfrac{\partial (r^{2}v_r)}{\partial r} + \dfrac{1}{r\sin\theta}\dfrac{\partial (v_\theta \sin\theta)}{\partial \theta} + \dfrac{1}{r\sin\theta}\dfrac{\partial v_\phi}{\partial \phi}$ | - -Cylindrical $\varrho=\sqrt{x^2+y^2}$ is the distance from the $z$-axis; spherical $r=\sqrt{x^2+y^2+z^2}$, used throughout this lab, is the distance from the origin. They are written differently precisely to keep them apart. - -One reading note: the spherical coordinates are named $(r,\phi,\theta)$, but the terms in the row above are listed as $r$, then $\theta$, then $\phi$, the order in which the scale factors $(1,\ r,\ r\sin\theta)$ are derived. The order of terms in a sum is immaterial. - -Both fields built so far are spherically symmetric, $\boldsymbol{E} = E_r(r)\,\hat{\boldsymbol{r}}$ with no $\theta$ or $\phi$ dependence, so two of the three spherical terms vanish and the divergence reduces to one ordinary derivative along one line: - -$$ \nabla\cdot\boldsymbol{E} \;=\; \frac{1}{r^{2}}\frac{d}{dr}\!\left(r^{2}E_r\right) $$ - -```{code-cell} ipython3 -dr = 0.005 -r_line = np.arange(0.05, 2.0 + dr, dr) # one radial line, not a cube - -# the same two fields as before, as functions of r alone -E_R_blob = rho_v0 / (epsilon_0 * r_line**2) * ( - (a**3 * np.sqrt(np.pi) / 4) * erf(r_line / a) - - (a**2 * r_line / 2) * np.exp(-r_line**2 / a**2)) -E_r_point = k_e * Q / r_line**2 - -div_blob_sph = np.gradient(r_line**2 * E_R_blob, dr) / r_line**2 -div_point_sph = np.gradient(r_line**2 * E_r_point, dr) / r_line**2 - -rho_v_line = rho_v0 * np.exp(-r_line**2 / a**2) - -# --- given: the radial profile Task 13 asserted but never drew --- -Q_total = np.pi**1.5 * rho_v0 * a**3 # all of the blob's charge -plt.figure(figsize=(5.8, 4.2)) -plt.plot(r_line, E_R_blob, "k", lw=1.8, label="$E_r(r)$, exact") -plt.plot(r_line, rho_v0 * r_line / (3 * epsilon_0), "C1--", lw=1.2, - label=r"small $r$: $\rho_{v0}r/3\varepsilon_0$") -plt.plot(r_line, Q_total / (4 * np.pi * epsilon_0 * r_line**2), "C2:", lw=1.4, - label=r"large $r$: $Q/4\pi\varepsilon_0 r^2$") -plt.axvline(a, color="C0", lw=1, alpha=0.6) -plt.annotate("$r = a$", (a, 1.12 * E_R_blob.max()), color="C0", ha="left") -plt.xlabel("$r$ [m]"); plt.ylabel(r"$E_r$ [V m$^{-1}$]") -plt.ylim(0, 1.25 * E_R_blob.max()); plt.grid(alpha=0.3); plt.legend(fontsize=8) -plt.title("The blob's field: linear inside, inverse-square outside") -plt.show() - -err_sph = np.abs(div_blob_sph - rho_v_line / epsilon_0)[1:-1] / np.max(rho_v_line / epsilon_0) -print(f"blob : {r_line.size} samples on a line vs {X.size:,} in the cube") -print(f" worst error {err_sph.max():.3%} of peak, median {np.median(err_sph):.4%}") -print(f" Cartesian, from Task 13: {cart_worst:.3%} and {cart_median:.4%}") -print(f"point: r^2 E_r varies by {np.ptp(r_line**2 * E_r_point):.1e} over the whole line") -print(f" max |div E| = {np.abs(div_point_sph).max():.1e} (round-off, not physics)") -``` - -:::{admonition} Why curvilinear coordinates are worth the trouble -:class: important - -Same field, same operator, same answer, obtained from a few hundred samples on a line rather than a quarter of a million in a cube, and several times more accurately. - -For the point charge the gain is certainty rather than accuracy. $r^{2}E_r = Q/4\pi\varepsilon_0$ is a **constant**, so its derivative is analytically zero for every $r>0$: not 1% of something, but zero, in one line of algebra. What the cell prints is the precision with which double arithmetic subtracts two equal numbers, around $10^{-13}$, or exactly $0$ when the cancellation is exact. Changing `dr` moves that last digit; it does not move the algebra. Cartesian coordinates could establish only that the divergence is small. - -Matching the coordinates to the symmetry of the source replaces three noisy numerical derivatives with one line of algebra. That is the purpose of the second and third rows of the table. -::: - ---- - -## Part 6 — Flux, and the divergence theorem - -Part 5 used the differential form of Gauss's law, which compares two numbers at one point. The integral form relates a volume to the surface enclosing it: - -$$ \oint_S \boldsymbol{E}\cdot\hat{\boldsymbol{n}}\,dS \;=\; \int_{\mathcal{D}} \nabla\cdot\boldsymbol{E}\;dV \;=\; \frac{Q_{\text{enc}}}{\varepsilon_0} $$ - -with $S$ the closed surface, $\hat{\boldsymbol{n}}$ its outward unit normal, and $\mathcal{D}$ the volume it encloses. - -The first equality is the **divergence theorem**, pure vector calculus, valid for any well-behaved field. The second is the physics. Together they state that measuring $\boldsymbol{E}$ on a closed surface gives the charge inside, and nothing about its arrangement or about any charge outside. - -Take $S$ to be a cube of half-width $h$ centred on the origin, faces on grid planes. On the $+x$ face the outward normal is $+\hat{\boldsymbol{x}}$, so it contributes $\int\!\!\int E_x\,dy\,dz$; on the $-x$ face the normal is $-\hat{\boldsymbol{x}}$ and the same integral enters negatively. Six faces, three pairs. - -### Task 14 — close the surface - -```{code-cell} ipython3 -# `fw.area_integral(F2, da, db)` integrates a 2-D array over the face it -# spans; `fw.volume_integral(F3, dx, dy, dz)` does the same over a box. -# `fw.box_indices(X, h)` gives the index range of the cube |x|,|y|,|z| <= h. -# -# The x pair is written for you; the pattern is one row per axis: -# -# face pair outward samples inward samples spacings -# x Ax[i1, s, s] Ax[i0, s, s] dy, dz -# y Ay[s, i1, s] Ay[s, i0, s] dx, dz -# z Az[s, s, i1] Az[s, s, i0] dx, dy -# -# The axis you pin to i0/i1 is the axis whose spacing you leave out. -# NOTE: this closes over X, dx, dy, dz from the cell above, so it is tied to -# this grid and is not a general-purpose function. - -def closed_box_flux(Ax, Ay, Az, half_width): - """Net outward flux through the cube |x|,|y|,|z| <= half_width.""" - i0, i1 = fw.box_indices(X, half_width) - s = slice(i0, i1 + 1) - flux_x = (fw.area_integral(Ax[i1, s, s], dy, dz) - - fw.area_integral(Ax[i0, s, s], dy, dz)) - flux_y = ___ - flux_z = ___ - return flux_x + flux_y + flux_z - - -# --- given: three routes to the same number, and the Task 12 arbiter --- -# Finish closed_box_flux above; everything below is written for you. -flux_1m = closed_box_flux(Ex_b, Ey_b, Ez_b, 1.0) - -print(f"{'h [m]':>6} {'surface':>12} {'volume':>12} {'Q_enc/eps0':>12}") -for h in (0.6, 1.0, 1.4): - i0, i1 = fw.box_indices(X, h) - s_ = slice(i0, i1 + 1) - surf = closed_box_flux(Ex_b, Ey_b, Ez_b, h) - vol = fw.volume_integral(div_blob[s_, s_, s_], dx, dy, dz) - qenc = fw.volume_integral(rho_v[s_, s_, s_], dx, dy, dz) / epsilon_0 - print(f"{h:6.1f} {surf:12.3f} {vol:12.3f} {qenc:12.3f}") - -# Task 12 settled by measurement rather than by argument. Both (b) and (c) -# appear to throw fluid outwards somewhere; a closed surface is the arbiter, -# and it differentiates nothing. -print(f"\nflux of (b), the rotation : {closed_box_flux(-Y, X, zero, 1.0):+.2e}") -print(f"flux of (c), the shear : {closed_box_flux(X, -Y, zero, 1.0):+.2e}") - -# --- self-check (leave this alone) --- -i0, i1 = fw.box_indices(X, 1.0) -s = slice(i0, i1 + 1) -fw.check_scalar("closed-surface flux = Q_enc/eps0", flux_1m, - fw.volume_integral(rho_v[s, s, s], dx, dy, dz) / epsilon_0, - rtol=0.01, unit=" V*m") -fw.check_scalar("divergence theorem: surface = volume", flux_1m, - fw.volume_integral(div_blob[s, s, s], dx, dy, dz), - rtol=0.01, unit=" V*m") -``` - -:::{admonition} Solution — Task 14 -:class: dropdown - -```python - flux_y = (fw.area_integral(Ay[s, i1, s], dx, dz) - - fw.area_integral(Ay[s, i0, s], dx, dz)) - flux_z = (fw.area_integral(Az[s, s, i1], dx, dy) - - fw.area_integral(Az[s, s, i0], dx, dy)) - return flux_x + flux_y + flux_z -``` -::: - -:::{admonition} Three routes, one number -:class: important - -Three independent calculations. The first never examines the interior of the box, the second never examines the surface, and the third never examines the field. They agree to a fraction of a percent. - -The result grows with $h$ and then stops: once the cube holds nearly all the charge, enlarging it adds surface but no charge. Charge outside a closed surface contributes exactly nothing, because the field lines it sends in through one wall leave through another. -::: - -### Shrinking the source to a point - -Run the same surface integral on the point-charge field of Task 7, whose divergence could not be measured at the origin because the singularity had to be masked. - -Rearranged, Gauss's law turns the flux into a **charge meter**: $Q_{\text{enc}} = \varepsilon_0 \oint_S \boldsymbol{E}\cdot\hat{\boldsymbol{n}}\,dS$. Weigh the charge inside each box in coulombs and compare it with the 1 nC placed there. - -```{code-cell} ipython3 -print("box half-width charge it finds") -for h in (0.6, 1.0, 1.4): - Q_found = epsilon_0 * closed_box_flux(Ex, Ey, Ez, h) - print(f" {h:.1f} m {Q_found * 1e12:8.2f} pC") -print(f"\n actually there {Q * 1e12:8.2f} pC") - -# The shell between the 0.6 m and 1.4 m boxes holds no charge. Weigh it: what -# enters the small box must leave the large one, so the difference of the two -# fluxes is the charge in between. -Q_shell = epsilon_0 * (closed_box_flux(Ex, Ey, Ez, 1.4) - - closed_box_flux(Ex, Ey, Ez, 0.6)) -print(f"\ncharge in the shell between them: {Q_shell * 1e12:+.2f} pC " - f"({abs(Q_shell) / Q:.2%} of the charge at the centre)") -``` - -:::{admonition} Where did the charge go? -:class: important - -Every box weighs the same 1 nC to a fraction of a percent, and the shell between two of them weighs nothing. All the charge lies in the only region common to every box: the origin. - -The whole source therefore sits at one point, where $\nabla\cdot\boldsymbol{E}$ is not a large number but undefined: $\rho_v$ has become a **Dirac delta**, zero everywhere, infinite at one point, with finite integral $Q$. The integral form survives exactly where the differential form fails. - -The same statement for magnetism carries no source term at all: - -$$ \nabla\cdot\boldsymbol{B} = 0 \qquad\Longleftrightarrow\qquad \oint_S \boldsymbol{B}\cdot\hat{\boldsymbol{n}}\,dS = 0 \ \ \text{for every closed } S $$ - -The measurement returns zero around any closed surface anywhere: there are no magnetic monopoles, and field lines of $\boldsymbol{B}$ never begin or end. -::: - -### The dipole, exactly - -Task 11 measured $\nabla\cdot\boldsymbol{B} = 0$ for the Earth's dipole and returned 1.8%, which is grid error rather than physics. The same claim can be tested without differentiating: put a closed surface around the dipole and weigh what crosses it. - -One warning before reading the numbers. A box centred on the origin is too easy a test for this dipole: with $\boldsymbol{m} = \hat{\boldsymbol{z}}$, $B_x$ and $B_y$ are odd in $z$ and $B_z$ is even, so on a $z$-symmetric box the faces cancel in pairs before any physics enters. An off-centre box is the honest test, and the cell below runs both. - -```{code-cell} ipython3 -r_dot_m = Z -Bx = 3*X*r_dot_m / r_safe**5 -By = 3*Y*r_dot_m / r_safe**5 -Bz = (3*Z*r_dot_m - r_safe**2) / r_safe**5 - -B = tuple(np.nan_to_num(q) for q in (Bx, By, Bz)) -v = tuple(np.nan_to_num(q / r_safe**3) for q in (X, Y, Z)) - -# --- given: the same surface integral over any grid-aligned box, centred -# on the origin or not. Same six faces, same three pairs as Task 14. -def box_flux(A, x0, x1, y0, y1, z0, z1): - i = [int(np.argmin(np.abs(axis - q))) for q in (x0, x1, y0, y1, z0, z1)] - sx, sy, sz = slice(i[0], i[1]+1), slice(i[2], i[3]+1), slice(i[4], i[5]+1) - return (fw.area_integral(A[0][i[1], sy, sz], dy, dz) - fw.area_integral(A[0][i[0], sy, sz], dy, dz) - + fw.area_integral(A[1][sx, i[3], sz], dx, dz) - fw.area_integral(A[1][sx, i[2], sz], dx, dz) - + fw.area_integral(A[2][sx, sy, i[5]], dx, dy) - fw.area_integral(A[2][sx, sy, i[4]], dx, dy)) - -boxes = [("centred, h = 0.6", (-0.6, 0.6, -0.6, 0.6, -0.6, 0.6)), - ("centred, h = 1.0", (-1.0, 1.0, -1.0, 1.0, -1.0, 1.0)), - ("centred, h = 1.4", (-1.4, 1.4, -1.4, 1.4, -1.4, 1.4)), - ("lopsided in z ", (-1.0, 1.0, -1.0, 1.0, -0.6, 1.0)), - ("lopsided in x, z", (-0.6, 1.0, -1.0, 1.0, -0.6, 1.0))] - -print(" box flux of B flux of the radial flow v") -for name, lim in boxes: - print(f" {name} {box_flux(B, *lim):+11.2e} {box_flux(v, *lim):+12.4f}") -print(f"\n 4*pi = {4*np.pi:.4f}; the integrator misses it by " - f"{4*np.pi - box_flux(v, -1, 1, -1, 1, -1, 1):.1e} on the flow") - -# --- self-check (leave this alone) --- -fw.check("the dipole encloses nothing -- even in a box that is not centred on it", - max(abs(box_flux(B, *lim)) for _, lim in boxes) < 1e-2) -fw.check("...and the same integrator does find the tap in the radial flow", - abs(box_flux(v, -1, 1, -1, 1, -1, 1) - 4*np.pi) < 0.01 * 4*np.pi) -``` - -:::{admonition} Two kinds of "divergence-free" -:class: important - -The radial flow returns $4\pi$ through every surface, whatever its size: there is a tap at the origin, and every box finds the same one, as every box found the same 1 nC above. - -The dipole returns **nothing** through any of them. On the three centred boxes the result is zero to machine precision, but the warning above applies: those boxes cancel the field against itself by symmetry and could return nothing else. The off-centre boxes are the measurement that counts, and they return $-2.5\times10^{-3}$ and $-2.2\times10^{-4}$. Compare the adjacent column: the same integrator, on the same grid, misses $4\pi$ by $6.8\times10^{-3}$ on the radial flow. **The flux of the dipole is zero to better than the accuracy this method achieves on anything.** - -The two divergence-free fields are therefore different statements. The flow has a tap that can be located by shrinking a surface onto it; the dipole has nothing to locate, at any size or placement of the surface. This is $\nabla\cdot\boldsymbol{B} = 0$ in the form that admits no exception, and it is why the integral form is worth constructing: it settles the question at the source, where the differential form had to be masked. -::: - -### Where do the 1% errors come from? - -Every derivative on this page is a centred difference, accurate to $O(\Delta x^{2})$: halving the spacing should reduce the error by four. Confirm it. The study is a single loop. - -```{code-cell} ipython3 -print(f"{'n':>4} {'dx [m]':>8} {'worst error':>12} {'ratio':>7}") -prev = None -for n_test in (21, 31, 41, 61): - ax_t = np.linspace(-L, L, n_test) - h_t = ax_t[1] - ax_t[0] - Xt, Yt, Zt = np.meshgrid(ax_t, ax_t, ax_t, indexing="ij") - rt = np.sqrt(Xt**2 + Yt**2 + Zt**2) - Rst = np.maximum(rt, 1e-12) - rho_t = rho_v0 * np.exp(-rt**2 / a**2) - E_Rt = rho_v0 / (epsilon_0 * Rst**2) * ( - (a**3 * np.sqrt(np.pi) / 4) * erf(Rst / a) - - (a**2 * Rst / 2) * np.exp(-Rst**2 / a**2)) - dv = divergence(E_Rt * Xt / Rst, E_Rt * Yt / Rst, E_Rt * Zt / Rst, h_t, h_t, h_t) - inner = np.zeros(Xt.shape, bool) - inner[2:-2, 2:-2, 2:-2] = True - e = np.nanmax(np.abs(dv[inner] - (rho_t / epsilon_0)[inner])) / np.nanmax(rho_t / epsilon_0) - ratio = "-" if prev is None else f"{prev / e:.2f}" - print(f"{n_test:>4} {h_t:>8.4f} {e:>11.2%} {ratio:>7}") - prev = e -``` - -:::{admonition} Second order, by measurement -:class: important - -Compare each ratio with the square of the spacing ratio: $1.5^2 = 2.25$ from $n=21$ to $31$, $1.33^2 = 1.78$ from $31$ to $41$, and $1.5^2 = 2.25$ from $41$ to $61$. - -The 1.06% in Task 13 is therefore not noise to be tolerated but a predictable quantity that can be reduced at a known cost, and the choice of $n = 61$ in Part 2 can now be audited rather than assumed. -::: - ---- - -## Closing - -The chain built in this lab, in one line: - -$$ \rho_v \;\longrightarrow\; V \;\xrightarrow{\ -\nabla\ }\; \boldsymbol{E} \;\xrightarrow{\ \nabla\cdot\ }\; \rho_v/\varepsilon_0 $$ - -- **Gradient.** Scalar in, vector out. Points along steepest increase, normal to the level surfaces, with length equal to the rate of increase. -- **Divergence.** Vector in, scalar out. Net flux per unit volume, which measures what is created at a point and nothing else. - -### The same two operators, elsewhere in ECT - -Electrostatics is a convenient place to learn this pair, not the only place to use it. Each row below gives a potential, its gradient, and a statement about sources. The numerical machinery written in this lab applies unchanged to all of them: - -| System | Potential | Field | Source equation | -| :--- | :--- | :--- | :--- | -| Electrostatics | $V$ [V] | $\boldsymbol{E} = -\nabla V$   [V/m] | $\nabla\cdot\boldsymbol{E} = \rho_v/\varepsilon_0$ | -| Gravitation | $\Phi$ [J/kg] | $\boldsymbol{g} = -\nabla \Phi$   [m/s$^2$] | $\nabla\cdot\boldsymbol{g} = -4\pi G\rho_m$ | -| Heat conduction | $T$ [K] | $\boldsymbol{q}_T = -k\nabla T$   [W/m$^2$] | $\nabla\cdot\boldsymbol{q}_T = 0$ (steady, no sources) | -| Groundwater flow | $h$ [m] | $\boldsymbol{q}_h = -K\nabla h$   [m/s] | $\nabla\cdot\boldsymbol{q}_h = 0$ (steady, incompressible) | - -with $k$ the thermal conductivity [W m$^{-1}$ K$^{-1}$] and $K$ the hydraulic conductivity [m/s]. - -The minus signs are all the same minus sign: heat flows from hot to cold, water flows from high head to low, a positive charge falls from high potential to low. Flow runs downhill, and the gradient points uphill. - -The last two rows show why solenoidal fields matter in practice. $\nabla\cdot\boldsymbol{q} = 0$ in an aquifer is not an approximation of convenience; it is conservation of water written locally. - -### What is still missing - -Return to field **(b)**, the rotation. Its divergence is zero everywhere, so by that measure it is indistinguishable from a field doing nothing. It nevertheless circulates, and every streamline closes on itself. - -The divergence cannot detect circulation. The operator that can is the **curl**, the third of the three operators this chapter is named after. - -### Homework - -The exercises in the lecture notes are the written homework. Below is the lab's computational extension, which carries the same two operators into a different physical system. - -**A heat source in a room.** Replace the spherical blob with a flat rectangular heater, $1.0 \times 0.6$ m in the $z = 0$ plane. A steady point source of power $P$ in a medium of conductivity $k$ raises the temperature above ambient by $P/4\pi k r$, the same $1/r$ used throughout this lab. Split the plate into $N = 20 \times 12$ sub-sources, give each an equal share $P/N$ of the power, and superpose them as two charges were superposed in Task 8: - -$$ T(\boldsymbol{r}) = \frac{P}{4\pi k N}\sum_{i=1}^{N} \frac{1}{\lvert \boldsymbol{r} - \boldsymbol{r}_i \rvert}, \qquad P = 100\ \text{W}, \qquad k_{\text{air}} = 0.026\ \text{W m}^{-1}\text{K}^{-1}. $$ - -Check the dimensions before coding: $[P]/[k] = \text{W}/(\text{W m}^{-1}\text{K}^{-1}) = \text{m}\cdot\text{K}$, divided by a distance, so $T$ comes out in kelvin. A temperature formula that does not reduce to kelvin contains an error. Then: - -- Plot the isosurfaces. Close to the plate they should be rounded rectangles; far away they should become spheres. Explain why the shape loses the imprint of its source. -- Compute the heat flux $\boldsymbol{q}_T = -k\nabla T$, with the same minus sign and the same reason as $\boldsymbol{E} = -\nabla V$. -- Check that $\nabla\cdot\boldsymbol{q}_T \approx 0$ away from the heater, and that the closed-surface flux through a box containing the plate is *not* zero. State what each result means physically for a room at steady state, and which of the two fields in Task 11 the heater resembles. -- **Then examine the number.** One metre from a 100 W panel this model predicts about $+290$ K above ambient, a room at 300 °C. The arithmetic is correct, so the physics is wrong. Identify the failed assumption; two are worth naming, namely what actually transports heat through air, and where this solution places the walls of the room. Re-running with $k = 1.5$ W m⁻¹K⁻¹, the conductivity of soil, gives $+5$ K: the same equations now describe a buried heating element, a problem that pure conduction does solve. diff --git a/book/1_gradient_divergence_curl/labs/week01_series_grad.md b/book/1_gradient_divergence_curl/labs/week01_series_grad.md new file mode 100644 index 0000000..6b07d9e --- /dev/null +++ b/book/1_gradient_divergence_curl/labs/week01_series_grad.md @@ -0,0 +1,882 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +mystnb: + # Workbook page: the task cells contain `___` blanks by design, so it must + # not be executed at build time. Readers run it themselves with Live Code. + execution_mode: 'off' +--- + +# Lab 1: Series and Gradient + +:::{admonition} Computer lab +:class: note + +A practical companion to the lectures on series, approximation and the gradient. Each task states a physical question, gives the steps, and ends with a self-check you can run. Plotting is supplied in the module `fwtools`, so that your effort goes into the physics rather than into rendering transparent isosurfaces. +::: + +## Learning objectives + +By the end of this lab you should be able to: + +- **Truncate a series and quantify what the truncation costs.** Sum a geometric series, approximate it by its leading term, determine how many terms a given accuracy requires, and identify where a Taylor series ceases to converge. +- **Read a gradient off a figure.** Show that $\nabla r = \hat{\boldsymbol{r}}$, that $\nabla f$ is normal to the level surfaces of $f$, and that $dp/dl = \lvert\nabla p\rvert\cos\psi$, so that the magnitude of the gradient is the maximum rate of change. +- **Convert a potential into a field, and a field into a survey.** Apply $\boldsymbol{E} = -\nabla V$ and Ohm's law $\boldsymbol{J} = -\rho^{-1}\nabla V$, and map the potential and current density of a two-electrode DC resistivity measurement. + +:::{admonition} Two labs +:class: note + +This is the first of two labs on the operators of this chapter. **Lab 2 covers the divergence and the curl**, and follows once those have been lectured. +::: + +--- + +## Part 0 — Setup + +Run this once. It contains no physics: it fetches two packages the browser lacks, locates `fwtools`, and defines the Coulomb constant. + +```{code-cell} ipython3 +# No physics above the k_e = ... line near the bottom. +import sys, pathlib + +import numpy as np +import matplotlib.pyplot as plt +from scipy.constants import epsilon_0 + +# --- Live Code housekeeping, not part of the physics ----------------------- +try: + import plotly.io as pio +except ModuleNotFoundError: + print("Fetching plotly. A few seconds, and only the first time...") + import micropip + await micropip.install("plotly") + import plotly.io as pio + +try: + import nbformat # noqa: F401 +except ModuleNotFoundError: + import micropip, types + try: + await micropip.install("nbformat") + except Exception: + _nb = types.ModuleType("nbformat") + _nb.__version__ = "5.10.4" + sys.modules["nbformat"] = _nb + +for _p in (".", "book/1_gradient_divergence_curl/labs"): + if (pathlib.Path(_p) / "fwtools.py").exists(): + sys.path.insert(0, _p) + break +try: + import fwtools as fw +except ModuleNotFoundError: + from pyodide.http import pyfetch + _r = await pyfetch("fwtools.py") + pathlib.Path("fwtools.py").write_bytes(await _r.bytes()) + import fwtools as fw + +pio.renderers.default = "plotly_mimetype+notebook" +# --------------------------------------------------------------------------- + +k_e = 1.0 / (4.0 * np.pi * epsilon_0) # Coulomb constant, 8.99e9 V*m/C +Q = 1e-9 # 1 nC test charge + +print(f"epsilon_0 = {epsilon_0:.4e} F/m") +print(f"k_e = {k_e:.4e} V*m/C") +``` + +--- + +## Part 1 — Series and truncation + +A physical quantity is often an infinite sum, of which only the first few terms are kept. Two questions follow: what the truncation costs, and whether the sum converges at all. + +### Task 1 — the bouncing ball + +A ball leaves the ground at $z=0$ with upward velocity $v_0$. Between bounces it is in free fall, + +$$ z(t) = v_0 t - \tfrac{1}{2}g t^2, $$ + +so it returns to the ground after $T_0 = 2v_0/g$ having reached a height $H = v_0^2/2g$. At each bounce it loses a fraction $\gamma$ of its energy, so $v_n = \sqrt{1-\gamma}\;v_{n-1}$, and since flight time is proportional to launch speed, + +$$ T_n = (1-\gamma)^{n/2}\,T_0, \qquad T_0 = \sqrt{8H/g}. $$ + +Fill in the three physical lines; the plotting is given. + +```{code-cell} ipython3 +g, v0, gamma = 9.81, 5.0, 0.1 +N = 12 # bounces to draw + +H = ___ # peak height of the first flight +T0 = ___ # duration of the first flight +T = T0 * ___ # durations of bounces 0 .. N-1 + +# --- given: draw one parabola per bounce --- +t_start = np.concatenate(([0.0], np.cumsum(T)[:-1])) +plt.figure(figsize=(9, 3.4)) +for Tn, t0 in zip(T, t_start): + tau = np.linspace(0, Tn, 200) + plt.plot(t0 + tau, (g*Tn/2)*tau - g*tau**2/2, "C0") +plt.xlabel("$t$ [s]"); plt.ylabel("$z$ [m]"); plt.grid(alpha=0.3) +plt.title(f"bouncing ball, $\\gamma$ = {gamma}") +plt.show() + +# --- self-check (leave this alone) --- +fw.check(f"H = {H:.4f} m", np.isclose(H, v0**2/(2*g)), "H = v0^2 / 2g") +fw.check(f"T0 = {T0:.4f} s", np.isclose(T0, 2*v0/g), "T0 = 2 v0 / g") +fw.check("T0 = sqrt(8H/g) too", np.isclose(T0, np.sqrt(8*H/g))) +fw.check(f"{N} bounce durations, shrinking", len(T) == N and T[-1] < T[0]) +``` + +:::{admonition} Solution — Task 1 +:class: dropdown + +```python +H = v0**2 / (2*g) +T0 = 2*v0 / g +T = T0 * (1 - gamma)**(np.arange(N)/2) +``` +::: + +The ball bounces for a total time + +$$ T_\infty = \sum_{m=0}^{\infty} T_m = T_0\sum_{m=0}^{\infty}\left(\sqrt{1-\gamma}\right)^{m} = \frac{\sqrt{8H/g}}{1-\sqrt{1-\gamma}}, $$ + +a geometric series with ratio $\sqrt{1-\gamma}$. The ratio is smaller than 1 for any real bounce, so the sum is **finite**: infinitely many bounces, completed in about twenty seconds. The convergence condition matters, and Task 2 examines a series that fails it. For small $\gamma$, the expansion $\sqrt{1-\gamma}\approx 1-\gamma/2$ reduces the sum to + +$$ T_\infty \approx \sqrt{8H/g}\;\frac{2}{\gamma}. $$ + +Both questions are answered below by measurement: **how accurate is that approximation**, and **how many bounces must be summed** before the running total reaches $T_\infty$? + +```{code-cell} ipython3 +rows = {} +print(f"{'gamma':>7} {'T_inf':>9} {'approx':>9} {'error':>7} {'n for 99%':>10}") +for gam in (0.5, 0.2, 0.1, 0.02): + T_inf = ___ # the exact sum, from the formula above + T_appr = ___ # the small-gamma approximation + + # --- given: how many bounces to reach 99% of T_inf --- + rows[gam] = (T_inf, T_appr) + cum = np.cumsum(T0 * (1 - gam)**(np.arange(4000)/2)) + n99 = int(np.argmax(cum >= 0.99*T_inf)) + 1 + print(f"{gam:>7.2f} {T_inf:>8.3f}s {T_appr:>8.3f}s " + f"{abs(T_appr-T_inf)/T_inf:>6.1%} {n99:>10}") + +# --- self-check (leave this alone) --- +# The closed form against a brute-force sum of 5000 bounces: one number by +# two routes, one of which never assumed the series converges. +_summed = np.sum(T0 * (1 - 0.1)**(np.arange(5000)/2)) +fw.check(f"your T_inf at gamma = 0.1 ({rows[0.1][0]:.3f} s) equals the " + f"brute-force sum ({_summed:.3f} s)", + np.isclose(rows[0.1][0], _summed, rtol=1e-6)) +fw.check(f"your approximation overshoots by 2.6% there " + f"({rows[0.1][1]/rows[0.1][0] - 1:.2%})", + np.isclose(rows[0.1][1]/rows[0.1][0], 1.0263, rtol=1e-3)) +``` + +:::{admonition} Solution — Task 1, continued +:class: dropdown + +```python + T_inf = np.sqrt(8*H/g) / (1 - np.sqrt(1 - gam)) + T_appr = np.sqrt(8*H/g) * 2 / gam +``` +::: + +:::{admonition} What the table says +:class: important + +At $\gamma = 0.5$ the leading-term approximation is 17% wrong; at $\gamma = 0.02$ it is 0.5%. Keeping only the first term is a claim about the regime, not about the algebra, and it has to be justified case by case. + +The term count runs the other way. The more nearly elastic the ball, the more bounces the same accuracy requires: 14 at $\gamma = 0.5$, 456 at $\gamma = 0.02$. The approximation is cheapest exactly where the summation is most expensive. The same trade-off appears in every numerical method in this course. +::: + +### Task 2 — where a Taylor series stops working + +A function that is smooth enough, and whose series sums back to it, can be written as a Taylor series about $x=0$, + +$$ f(x) = f(0) + x f'(0) + \tfrac{1}{2}x^2 f''(0) + \cdots . $$ + +In practice the series is truncated after a few terms. Compare two cases: + +$$ \sin x = x - \frac{x^3}{3!} + \frac{x^5}{5!} - \cdots, \qquad\qquad \frac{1}{1+x} = 1 - x + x^2 - x^3 + \cdots $$ + +The two expansions look equally harmless. Add terms to each and compare. + +```{code-cell} ipython3 +x = np.linspace(-3, 3, 600) + +# term m of each series, as a function of x +def sin_term(m, x): + return 0.0 if m % 2 == 0 else ___ # (-1)^((m-1)/2) x^m / m! [math.factorial] + +def geo_term(m, x): + return ___ # term m of 1 - x + x^2 - ... + +# --- given: exact curve plus four truncations, side by side --- +fig, axes = plt.subplots(1, 2, figsize=(11, 4)) +for ax, (name, exact, term) in zip(axes, [ + (r"$\sin x$", np.sin, sin_term), + (r"$1/(1+x)$", lambda x: 1/(1+x), geo_term)]): + ax.plot(x, exact(x), "k", lw=2, label="exact") + for M in (2, 4, 8, 16): + ax.plot(x, sum(term(m, x) for m in range(M + 1)), lw=1, label=f"M = {M}") + ax.set_ylim(-3, 3); ax.set_xlabel("$x$"); ax.set_title(name) + ax.grid(alpha=0.3); ax.legend(fontsize=8) +plt.tight_layout() +plt.show() + +# --- self-check (leave this alone) --- +_s21 = sum(sin_term(m, x) for m in range(21)) +_g_in = sum(geo_term(m, 0.5) for m in range(40)) +_g_out = sum(geo_term(m, 1.5) for m in range(40)) +fw.check("21 terms reproduce sin(x) on -3 < x < 3", np.max(np.abs(_s21 - np.sin(x))) < 1e-6) +fw.check(f"1/(1+x) converges at x = 0.5 ({_g_in:.4f} vs {1/1.5:.4f})", np.isclose(_g_in, 1/1.5)) +fw.check(f"1/(1+x) diverges at x = 1.5 (partial sum {_g_out:.2e})", abs(_g_out) > 1e3) +``` + +:::{admonition} Solution — Task 2 +:class: dropdown + +```python +import math + +def sin_term(m, x): + return 0.0 if m % 2 == 0 else (-1)**((m-1)//2) * x**m / math.factorial(m) + +def geo_term(m, x): + return (-x)**m +``` +::: + +:::{admonition} Radius of convergence +:class: important + +$\sin x$ improves everywhere as terms are added. $1/(1+x)$ improves only inside $\lvert x\rvert < 1$; outside, each extra term makes the partial sum worse without limit, and at $x = 1.5$ the 40-term partial sum is off by millions. + +The series has a **radius of convergence** of 1, and no amount of computing power extends it. The radius is the distance from the expansion point to the nearest singularity of the function, here from $x=0$ to the pole at $x=-1$. The failure is invisible at $x = 0$ itself, where the function is smooth and the first few terms behave well. Expanding about $x = 1$ instead gives a radius of 2, because the pole is then twice as far away. **The radius is set by where the function is singular, not by its behaviour at the expansion point.** + +Compare Task 1, where more terms always helped and the only question was how many. Here, beyond $\lvert x\rvert = 1$, more terms are useless. Establishing which case applies is a prerequisite to any truncation. +::: + +--- + +## Part 2 — The distance function and its gradient + +All remaining parts use a single cube of sample points. + +```{code-cell} ipython3 +n, L = 61, 2.0 # odd n, so the origin is a sample point +axis = np.linspace(-L, L, n) # one axis, shared by x, y and z +X, Y, Z = np.meshgrid(axis, axis, axis, indexing="ij") +dx = dy = dz = axis[1] - axis[0] + +c = n // 2 # index of the origin +# Mask reused by the self-checks. `interior` drops the two outermost cells, +# so comparisons exclude the six faces of the box, where sampling is worst +# and np.gradient has only one-sided neighbours. +interior = np.zeros(X.shape, dtype=bool) +interior[2:-2, 2:-2, 2:-2] = True + +print(f"grid shape {X.shape}, spacing {dx:.4f} m, {X.size:,} sample points") +print(f"X[i,j,k] = x[i] -> X[-1, 0, 0] = {X[-1, 0, 0]:.1f} m") +``` + +:::{admonition} Grid convention +:class: tip + +**Resolution.** Every derivative on this page is a centred difference, so its error falls as $\Delta x^{2}$. Measured worst-case error against the analytic answer: + +| $n$ | $\Delta x$ [m] | $\lvert\nabla r\rvert$ | $\nabla(1/r)$ | $\nabla\cdot\boldsymbol{E}$ | +| ---: | ---: | ---: | ---: | ---: | +| 21 | 0.200 | 4.1% | 12.5% | 9.1% | +| 41 | 0.100 | 1.8% | 3.3% | 2.4% | +| **61** | **0.067** | **0.8%** | **1.6%** | **1.1%** | +| 81 | 0.050 | 0.5% | 1.0% | 0.6% | + +These are **worst cases** over the region each self-check tests, not averages, and they are what fixes the tolerances. Halving $\Delta x$ reduces the last two columns by close to the factor of four that second-order accuracy predicts (12.5 → 3.3, 9.1 → 2.4). The first column falls by only 2.3. The $|\nabla r|$ error grows towards the source, so the worst sample in the band $0.4 < r < 1.6$ m is whichever one sits nearest the inner edge, and that sample moves when `n` changes. A worst case taken over a boundary that the grid keeps redrawing does not form a smooth sequence. The convergence cell at the end of Lab 2 measures a fixed quantity instead and does recover the factor of four. + +$n = 61$ was chosen from this table as the coarsest grid that keeps every task under 2%; each 3-D figure it produces is about 1.5 MB. **If you change `n`, keep it at 41 or above.** The self-checks below allow 5%, and $n = 31$ already fails Task 6 at 6.7%. + +Two properties of this cube matter later. It is a finite window on fields that extend to infinity: the largest closed surface in Lab 2 sits only 0.6 m inside the outer face. And $z$ points **up**, as in an ordinary right-handed frame, whereas Part 4 works in the ground, where $z$ points downwards by Earth-science convention. Neither choice is more correct; stating which one is in use is what matters. + +The grid is built with `indexing='ij'`, so axis 0 is $x$, axis 1 is $y$, axis 2 is $z$. + +1. **Derivatives come back in coordinate order:** `np.gradient(f, dx, dy, dz)` returns $\partial f/\partial x$, $\partial f/\partial y$, $\partial f/\partial z$. No transposes. +2. **Always pass the spacings.** Omit them and the derivative is silently wrong by a factor of $1/\Delta x = 15$. + +NumPy's default is `indexing='xy'`, which returns the $y$-derivative first. That single difference accounts for a large share of numerical field bugs. +::: + +The simplest scalar field is the distance to a point: + +$$ r(x,y,z) = \sqrt{(x-x_0)^2 + (y-y_0)^2 + (z-z_0)^2} $$ + +One number at every location in space: no charge, no potential, and no units beyond metres. + +This is the **spherical** radial coordinate $r$, the distance from a point. The cylindrical radius $\varrho$, the distance from an axis, is a different quantity. The equations on this page use $r$, and the code calls it `r`. + +### Task 3 — build the distance field + +**The question:** what do the surfaces of constant $r$ look like, and where do they crowd together? + +The source must be movable: Task 8 places two of them at different points, so write the offsets in now rather than hard-coding the origin. + +```{code-cell} ipython3 +# Task 3 -- distance from a source at (x0, y0, z0) to every point of the grid. + +def distance_to(X, Y, Z, x0=0.0, y0=0.0, z0=0.0): + return ___ # root of the sum of three squares + + +r = ___ # call it: one source, at the origin + +# --- self-check (leave this alone) --- +fw.check_shape("r", r, X.shape) +fw.check("r = 0 at the origin", np.isclose(r[c, c, c], 0.0)) +fw.check("r = 2 m at (2,0,0)", np.isclose(r[-1, c, c], 2.0)) +fw.check("r = 2 m at (0,2,0)", np.isclose(r[c, -1, c], 2.0)) +fw.check("the source can be moved off the origin", + np.isclose(distance_to(X, Y, Z, 1.0, 0.0, 0.0)[c, c, c], 1.0), + "x0, y0, z0 have to appear in the expression -- Task 8 needs them") +``` + +:::{admonition} Solution — Task 3 +:class: dropdown + +```python +def distance_to(X, Y, Z, x0=0.0, y0=0.0, z0=0.0): + return np.sqrt((X - x0)**2 + (Y - y0)**2 + (Z - z0)**2) + + +r = distance_to(X, Y, Z) +``` +::: + +A surface on which $r$ takes one fixed value is an **isosurface**, or level set, the three-dimensional analogue of a contour line on a map. Evenly spaced values of $r$ give evenly spaced shells: the distance function has no preferred radius. + +```{code-cell} ipython3 +fw.show_isosurfaces(X, Y, Z, r, levels=[0.5, 1.0, 1.5], label="r [m]", + title="Isosurfaces of the distance function r") +``` + + +### Task 4 — the gradient of the distance + +Do this one on paper first. Differentiating $r = \sqrt{x^2+y^2+z^2}$ by the chain rule, + +$$ \frac{\partial r}{\partial x} = \frac{x}{r}, \qquad \frac{\partial r}{\partial y} = \frac{y}{r}, \qquad \frac{\partial r}{\partial z} = \frac{z}{r} $$ + +so, collecting the three components, + +$$ \nabla r \;=\; \frac{\partial r}{\partial x}\hat{\boldsymbol{x}} + \frac{\partial r}{\partial y}\hat{\boldsymbol{y}} + \frac{\partial r}{\partial z}\hat{\boldsymbol{z}} \;=\; \frac{x\,\hat{\boldsymbol{x}} + y\,\hat{\boldsymbol{y}} + z\,\hat{\boldsymbol{z}}}{r} \;=\; \hat{\boldsymbol{r}} $$ + +The last step is the definition of the outward unit radial vector: $\hat{\boldsymbol{r}}$ is the position vector divided by its own length. So $\nabla r$ is a **unit** vector pointing **away** from the source, with both direction and magnitude known in advance. + +The cell below tests whether a **finite-difference gradient** on a grid reproduces that. Two measurements: the magnitude, which should be 1, and the projection $\nabla r \cdot \hat{\boldsymbol{r}}$, which recovers the full magnitude only if the gradient is purely radial, with no component along the sphere. + +```{code-cell} ipython3 +# The outward unit radial vector, used again later. +rs = np.maximum(r, 1e-12) # 0/0 at the source is not a lesson +rhx, rhy, rhz = X / rs, Y / rs, Z / rs + +# Task 4 +# 1. grad r, as three components. +# 2. Its magnitude. +# 3. Its projection onto r-hat. +# 4. Draw it, rotate the figure, and compare with the spheres above. + +grx, gry, grz = ___ # all three spacings, in order + +grad_r_mag = ___ # the length of that vector + +radial_part = ___ # its projection onto (rhx, rhy, rhz) + +fw.show_cones(X, Y, Z, grx, gry, grz, step=8, label="|∇r|", unit="-", + title="grad r -- unit vectors pointing away from the source") + +# --- self-check (leave this alone) --- +band = (r > 0.4) & (r < 1.6) +fw.check_shape("grad r (x-component)", grx, X.shape) +fw.check_close("|grad r| = 1 everywhere", grad_r_mag, 1.0, rtol=0.05, where=band) +fw.check_close("grad r is purely radial", radial_part, 1.0, rtol=0.05, where=band) +# The two checks above are the same measurement for THIS field, so they pass +# or fail together. This one is independent: it compares the three components +# against r-hat separately, catching a gradient of the right length but the +# wrong direction. +fw.check(f"grad r = r-hat, componentwise (worst " + f"{np.nanmax(np.abs(np.stack([grx-rhx, gry-rhy, grz-rhz]))[:, band]):.3f} " + f"of a unit vector)", + np.nanmax(np.abs(np.stack([grx - rhx, gry - rhy, grz - rhz]))[:, band]) < 0.05) +``` + +:::{admonition} Solution — Task 4 +:class: dropdown + +```python +grx, gry, grz = np.gradient(r, dx, dy, dz) +grad_r_mag = np.sqrt(grx**2 + gry**2 + grz**2) +radial_part = grx * rhx + gry * rhy + grz * rhz + +print(f"|grad r| median in 0.4 < r < 1.6 m : " + f"{np.median(grad_r_mag[(r > 0.4) & (r < 1.6)]):.4f}") +``` +::: + +:::{admonition} What the algebra means +:class: important + +$\lvert\nabla r\rvert = 1$ needs no calculus: move one metre directly away from the source and the distance to it grows by one metre, so the steepest rate of change of $r$ is 1 m/m everywhere. A gradient carries the direction of steepest increase and a length equal to that rate, here outward and 1. + +The radial check fixes the other half: moving along a sphere does not change $r$, so the gradient has no component there. **$\nabla f$ is normal to the level surfaces of $f$** for every scalar field, not only this one. + +::: + +### Task 5 — the rate of change in an arbitrary direction + +The direction of the gradient is settled: steepest increase, normal to the level surface. Its magnitude is the untested claim. It follows from + +$$ dp = (\nabla p)\cdot d\boldsymbol{l} = \lvert\nabla p\rvert\,\lvert d\boldsymbol{l}\rvert\cos\psi +\qquad\Longrightarrow\qquad +\frac{dp}{dl} = \lvert\nabla p\rvert\cos\psi, $$ + +where $d\boldsymbol{l}$ is a small step in any chosen direction, $dl = \lvert d\boldsymbol{l}\rvert$ is its length, and $\psi$ is the angle between the step and the gradient. The step is written $d\boldsymbol{l}$ rather than $d\boldsymbol{r}$ because $r$ already denotes the distance from the origin on this page. + +Two testable consequences: the rate of change in any direction is $\lvert\nabla p\rvert\cos\psi$, and it never exceeds $\lvert\nabla p\rvert$, which is reached only at $\psi = 0$. + +Measure it. At one point, step a short distance $\varepsilon$ along many unit vectors $\hat{\boldsymbol{u}}$ and compare each measured rate with the prediction. + +```{code-cell} ipython3 +p_field = 1.0 / np.maximum(r, 0.25) # any scalar field will do +gpx, gpy, gpz = np.gradient(p_field, dx, dy, dz) + +ip, jp, kp = 40, 36, 34 # one sample point, off-axis +gvec = np.array([gpx[ip, jp, kp], gpy[ip, jp, kp], gpz[ip, jp, kp]]) +point = np.array([axis[ip], axis[jp], axis[kp]]) + +def p_exact(q): + return 1.0 / np.linalg.norm(q) # the same field, evaluated anywhere + +# Task 5 -- fill in the four blanks; the plotting is given. +grad_mag = ___ # |grad p| at the point, from gvec + +rng = np.random.default_rng(0) +eps = 1e-4 +cosines, rates = [], [] +for _ in range(200): + u = rng.normal(size=3) + u = ___ # make it a UNIT vector + cosines.append(___) # cos(psi) = u . gvec / |grad p| + rates.append(___) # centred difference of p_exact + # along u, step eps, over 2*eps +cosines, rates = np.asarray(cosines), np.asarray(rates) + +# --- given: measurements against the predicted straight line --- +plt.figure(figsize=(5.6, 4.4)) +plt.scatter(cosines, rates, s=12, alpha=0.6, label="measured") +cs = np.linspace(-1, 1, 50) +plt.plot(cs, grad_mag*cs, "k", lw=1.5, label=r"$|\nabla p|\cos\psi$") +plt.xlabel(r"$\cos\psi$") +plt.ylabel(r"$dp/dl$ [m$^{-2}$]") +plt.legend(); plt.grid(alpha=0.3) +plt.show() + +# --- self-check (leave this alone) --- +slope = float(np.polyfit(cosines, rates, 1)[0]) +fw.check_scalar("fitted slope = |grad p|", slope, grad_mag, rtol=0.01) +fw.check("no direction beats |grad p|", np.max(np.abs(rates)) <= grad_mag * 1.001) +``` + +:::{admonition} Solution — Task 5 +:class: dropdown + +```python +grad_mag = float(np.linalg.norm(gvec)) + +# ... and inside the loop: + u = u / np.linalg.norm(u) + cosines.append(float(u @ gvec) / grad_mag) + rates.append((p_exact(point + eps*u) - p_exact(point - eps*u)) / (2*eps)) +``` +::: + +:::{admonition} The magnitude, measured +:class: important + +Every measured rate lies on the line. Three readings of the same figure: + +- **At $\cos\psi = 1$** the step is straight up the gradient and the rate equals $\lvert\nabla p\rvert$. No direction exceeds it, which is the content of *steepest*, now measured rather than asserted. +- **At $\cos\psi = 0$** the step lies in the level surface and $p$ does not change. This is the normality result of Task 4, recovered by a second route. +- **At $\cos\psi = -1$** the rate is $-\lvert\nabla p\rvert$, the steepest descent, which is the direction $\boldsymbol{E} = -\nabla V$ selects in Part 3. + +One vector carries both a direction and a rate; the cosine gives the rate along any other direction. +::: + +--- + +## Part 3 — The inverse distance + +The function that appears in the physics is not the distance but its reciprocal, + +$$ f(r) = \frac{1}{r}, \qquad\text{so}\qquad \nabla f = \frac{d}{dr}\!\left(\frac{1}{r}\right)\hat{\boldsymbol{r}} = -\frac{1}{r^{2}}\,\hat{\boldsymbol{r}} $$ + +The isosurfaces are the same spheres, since $f$ is constant wherever $r$ is constant, but the ordering is inverted: $f$ is largest near the source and decays to zero far away. Predict the effect on the arrows, check the prediction against the formula above, then measure it. + +### Task 6 — the gradient of the inverse distance + +```{code-cell} ipython3 +# The mask keeps the singularity at r = 0 off the grid: everything within +# 0.25 m of the source becomes NaN and is not measured. +r_masked = np.where(r < 0.25, np.nan, r) +f = 1.0 / r_masked + +# Task 6 -- two blanks. Predict the direction before you look at the figure. +fx, fy, fz = ___ # grad f +f_mag = ___ # its magnitude, to compare with 1/r^2 + +# --- given: the numbers, then the picture --- +for rr in (0.6, 1.0, 1.5): + i = int(np.argmin(np.abs(X[:, 0, 0] - rr))) + print(f"r = {rr:.1f} m : |grad f| = {f_mag[i, c, c]:8.4f} 1/r^2 = {1/rr**2:8.4f}") + +# normalise=True draws every arrow the same length, so the figure carries +# direction only. The magnitude moves into the colour, on a log scale, +# because the drawn arrows span a factor of 62. +fw.show_cones(X, Y, Z, fx, fy, fz, step=8, normalise=True, + label="|∇(1/r)|", unit="m-2", + title="grad(1/r) -- pointing back towards the source") + +# --- self-check (leave this alone) --- +outside = (r > 0.5) & interior # `interior` was built in Part 2 +fw.check_close("|grad(1/r)| = 1/r^2", f_mag, 1.0 / r_masked**2, rtol=0.05, where=outside) +fw.check("grad(1/r) points inward at (1,0,0)", fx[-1 - 15, c, c] < 0) +``` + +:::{admonition} Solution — Task 6 +:class: dropdown + +```python +fx, fy, fz = np.gradient(f, dx, dy, dz) +f_mag = np.sqrt(fx**2 + fy**2 + fz**2) +``` +::: + +:::{admonition} The gradient always points towards increase +:class: important + +The arrows have reversed. Same spheres, same source, opposite direction: + +$$ \nabla r = +\hat{\boldsymbol{r}}, \qquad\qquad \nabla\!\left(\frac{1}{r}\right) = -\frac{1}{r^{2}}\,\hat{\boldsymbol{r}} $$ + +Nothing about space changed; what changed is **which way the function climbs**. The steepness changed as well: $1/r$ climbs faster as the source is approached, so its gradient grows as $1/r^2$ instead of staying at 1. + +A gradient encodes nothing about sources, sinks, charges or fields. It encodes only the uphill direction and the rate along it. +::: + +### Task 7 — from geometry to physics + +The physics enters as a single minus sign. The electric potential of a point charge $Q$ is the inverse-distance function with a constant in front, + +$$ V(r) = \frac{1}{4\pi\varepsilon_0}\frac{Q}{r}\quad[\text{V}], $$ + +and the electric field is *defined* as + +$$ \boldsymbol{E} = -\nabla V \quad[\text{V/m}]. $$ + +$\nabla V$ points inward, uphill towards the charge. The minus sign reverses it, so **the field points downhill**, which is the direction a positive test charge released from rest would move, losing potential energy as it goes. + +```{code-cell} ipython3 +V = k_e * Q / r_masked + +# Task 7 -- two blanks. Mind the minus sign. +Ex, Ey, Ez = ___ # E = -grad V +E_mag = ___ + +# --- given: against the analytic k_e*Q/r^2, then the picture --- +for rr in (0.6, 1.0, 1.5): + i = int(np.argmin(np.abs(X[:, 0, 0] - rr))) + print(f"r = {rr:.1f} m : |E| = {E_mag[i, c, c]:8.3f} V/m " + f"analytic = {k_e*Q/rr**2:8.3f} V/m") + +fw.show_cones(X, Y, Z, Ex, Ey, Ez, step=8, normalise=True, + label="|E|", unit="V/m", + title="E = -grad V for a positive point charge") + +# --- self-check (leave this alone) --- +fw.check_close("|E| = Q/(4 pi eps0 r^2)", E_mag, k_e * Q / r_masked**2, + rtol=0.05, where=outside) +fw.check("E points outward at (1,0,0)", Ex[-1 - 15, c, c] > 0) +``` + +:::{admonition} Solution — Task 7 +:class: dropdown + +```python +dVdx, dVdy, dVdz = np.gradient(V, dx, dy, dz) +Ex, Ey, Ez = -dVdx, -dVdy, -dVdz +E_mag = np.sqrt(Ex**2 + Ey**2 + Ez**2) +``` +::: + +:::{admonition} Why the potential is worth defining +:class: tip + +$V$ is a scalar: one number per point, with no direction to track. $\boldsymbol{E}$ is a vector: three numbers. Any operation carried out once on $V$ and then differentiated is cheaper, in arithmetic and in bookkeeping, than the same operation carried out three times on $\boldsymbol{E}$. + +Part 4 is the first case where this matters. +::: + +--- + +## Part 4 — Two sources: superposition + +A single charge is spherically symmetric. Two are not: + +$$ V_{\text{total}} = \frac{1}{4\pi\varepsilon_0}\left(\frac{Q_1}{r_1} + \frac{Q_2}{r_2}\right) $$ + +**Superposition** of potentials is the addition of two numbers at every point, because $V$ is a scalar. Superposing the two fields instead requires a vector sum at every point of the cube. + +Since $\nabla$ is linear, $-\nabla(V_1 + V_2) = \boldsymbol{E}_1 + \boldsymbol{E}_2$ exactly. The efficient route is therefore to **add the potentials and take a single gradient at the end**, with no loss of accuracy. + +### Task 8 — build a dipole + +```{code-cell} ipython3 +# Distances to the two charges. +Q sits at x = +d/2, -Q at x = -d/2, the same +# placement Task 9 gives the current source and sink, so the two figures can +# be compared directly. The guard trips only if a grid point lands exactly on +# a charge; at n = 61 none does, so nothing is masked and the full field is +# shown. Raise it if you change the grid. +d_sep = 1.0 # charge separation [m] +r_plus = np.where(distance_to(X, Y, Z, +d_sep/2, 0.0, 0.0) < 0.01, np.nan, + distance_to(X, Y, Z, +d_sep/2, 0.0, 0.0)) +r_minus = np.where(distance_to(X, Y, Z, -d_sep/2, 0.0, 0.0) < 0.01, np.nan, + distance_to(X, Y, Z, -d_sep/2, 0.0, 0.0)) + +# Task 8 -- two blanks. +V_dip = ___ # superpose: +Q over r_plus, -Q over r_minus +Ex_d, Ey_d, Ez_d = ___ # ONE gradient of the sum, negated + +# --- given: the z = 0 plane, potential as colour, field as streamlines --- +fw.show_field_slice(X, Y, Z, Ex_d, Ey_d, background=V_dip, + title="Source and sink: potential (colour) and field lines", + label="$V$ [V]") +plt.show() + +# --- self-check (leave this alone) --- +mid = np.abs(X) < 1e-9 # the plane x = 0, halfway between them +fw.check_shape("V_dip", V_dip, X.shape) +fw.check("V = 0 on the mid-plane", + np.nanmax(np.abs(V_dip[mid])) < 1e-6 * np.nanmax(np.abs(V_dip))) +fw.check("E on the mid-plane points from + to -", np.nanmean(Ex_d[mid]) < 0) +``` + +:::{admonition} Solution — Task 8 +:class: dropdown + +```python +V_dip = k_e * Q / r_plus + k_e * (-Q) / r_minus + +dVx, dVy, dVz = np.gradient(V_dip, dx, dy, dz) +Ex_d, Ey_d, Ez_d = -dVx, -dVy, -dVz +``` +::: + +:::{admonition} The mid-plane +:class: tip + +At $x = 0$ the potential is **exactly zero**, while the field is at its strongest, pointing straight from the positive charge to the negative one, here along $-\hat{\boldsymbol{x}}$ because $+Q$ sits on the right. + +The field is the slope of the potential, not its value: terrain at sea level can still be steep. The figure also shows the streamlines crossing the coloured contours at right angles everywhere, which is the normality result of Task 4 appearing in a field that was not constructed radially. +::: + +### The far field of the dipole + +$V_{\text{dip}}$ is not a series; it is two exact terms. Viewed from far enough away, however, the two charges are no longer resolvable, and what survives is a **truncation**. + +Expand $1/r_\pm$ in powers of $d/r$ and add. The leading terms are equal and opposite, since the pair carries no net charge, and the first surviving term is + +$$ V \;\approx\; \frac{1}{4\pi\varepsilon_0}\frac{\boldsymbol{p}\cdot\hat{\boldsymbol{r}}}{r^{2}}, \qquad \boldsymbol{p} = Q d\,\hat{\boldsymbol{x}}, $$ + +with the **dipole moment** $\boldsymbol{p}$ pointing from the negative charge to the positive one. Every discarded term is smaller by a further factor of $(d/r)^2$. This is the question of Task 1 asked of distance rather than of term count: at what range is one term enough? + +```{code-cell} ipython3 +# --- given: exact against the one-term far field, along the +x axis --- +p_mom = Q * d_sep # dipole moment [C m] +r_ff = np.logspace(np.log10(0.8), np.log10(60), 2000) +V_ex = k_e * Q * (1/np.abs(r_ff - d_sep/2) - 1/np.abs(r_ff + d_sep/2)) +V_ff = k_e * p_mom / r_ff**2 # p . r-hat = p on the axis +err_ff = np.abs(V_ff - V_ex) / np.abs(V_ex) + +plt.figure(figsize=(5.8, 4.2)) +plt.loglog(r_ff / d_sep, err_ff, "k", lw=1.6) +for tol, colour in ((0.10, "C1"), (0.01, "C2"), (0.001, "C3")): + r_ok = r_ff[np.argmax(err_ff < tol)] / d_sep + plt.axhline(tol, color=colour, lw=0.8, ls=":") + plt.plot([r_ok], [tol], "o", color=colour, ms=5) + print(f" one term is good to {tol:6.1%} beyond r = {r_ok:5.1f} separations") +plt.xlabel("$r$ / separation $d$"); plt.ylabel("relative error of the one-term form") +plt.grid(alpha=0.3, which="both"); plt.title("How far is far?") +plt.show() + +# --- self-check (leave this alone) --- +fw.check("the far-field error falls as (d/r)^2", + np.isclose(np.polyfit(np.log(r_ff[r_ff > 10]), np.log(err_ff[r_ff > 10]), 1)[0], + -2.0, atol=0.05)) +``` + +:::{admonition} The same question as the bouncing ball +:class: important + +Two decades of accuracy cost a factor of ten in distance: 10% at $1.6\,d$, 1% at $5\,d$, 0.1% at $16\,d$. This is the $(d/r)^2$ law, and the factor between successive rows is $\sqrt{10}\approx 3.2$. + +Compare Task 1, where 1% accuracy required 88 terms, and the count grew as the ball became more elastic. Here the controlling variable is a distance rather than a term count, and the requirement grows the closer the observation point. In both cases the truncation is only as good as the regime, and in both cases the regime can be established by measurement. + +This single term is why a compass works. A magnet has a complicated field close up; at a metre it is a dipole and nothing else, which is why the Earth's field is written as the single term used in Lab 2's Task 2. +::: + +The same object in three dimensions, with positive and negative equipotential surfaces drawn transparent: + +```{code-cell} ipython3 +lobe = np.nanpercentile(np.abs(V_dip), 97) +fw.show_isosurfaces(X, Y, Z, np.nan_to_num(V_dip), levels=[-lobe, -lobe/3, lobe/3, lobe], + colorscale="RdBu", reversescale=True, opacity=0.3, label="V [V]", + title="Equipotential surfaces of a dipole") +``` + +### Task 9 — the same mathematics as a geophysical survey + +Task 8 was two charges in vacuum. The mathematics below is identical; the physics is not. + +Drive a current $I$ into the ground through one electrode and extract it through another, a distance $a$ away. Air does not conduct, so in ground of resistivity $\rho$ the current spreads through the **lower half-space only**, and each electrode contributes $\rho I/2\pi r$ rather than $\rho I / 4\pi r$. Superposition gives + +$$ V(x,y,z) = \frac{\rho I}{2\pi}\left(\frac{1}{\lvert\boldsymbol{r}-\boldsymbol{a}/2\rvert} - \frac{1}{\lvert\boldsymbol{r}+\boldsymbol{a}/2\rvert}\right), \qquad z \ge 0 \ \text{(down into the ground)}. $$ + +The field follows as before, $\boldsymbol{E} = -\nabla V$, and Ohm's law in local form turns it into a **current density**: + +$$ \boldsymbol{J} = \rho^{-1}\boldsymbol{E} = -\rho^{-1}\nabla V \quad [\text{A}/\text{m}^2]. $$ + +This is a DC resistivity survey, a standard near-surface geophysical measurement. Map it two ways: on the ground surface, where the electrodes are planted, and on a vertical section cut between them. + +:::{admonition} $\rho$ means something else here +:class: warning + +In this task $\rho$ is the **electrical resistivity** in Ω·m. In Lab 2's Task 4 it is a charge density in C/m³, written $\rho_v$ to keep the two apart. The symbol is overloaded throughout the subject; the units identify which is meant. +::: + +The ground is a half-space, so this task needs its own grid: $x$ and $y$ still run from $-L$ to $L$, but $z$ runs from $0$ at the surface **downwards**, following the Earth-science convention. + +A real electrode is a metal stake, not a mathematical point: a conductor of finite radius $r_{\text{el}}$ held at one potential over its whole surface. Flooring the distance at $r_{\text{el}}$ models it that way and keeps $1/r$ bounded. Nothing is masked, no sample is discarded, and every derivative below acts on a field that is finite everywhere. + +```{code-cell} ipython3 +rho, I, a_sep = 100.0, 1.0, 1.0 # ohm.m, ampere, electrode spacing [m] +r_el = 0.12 # electrode radius [m] + +axis_g = np.linspace(-2.0, 2.0, 81) # x and y, across the survey line +depth = np.linspace(0.0, 2.0, 51) # z, down into the ground +Xg, Yg, Zg = np.meshgrid(axis_g, axis_g, depth, indexing="ij") +dxg = axis_g[1] - axis_g[0] +dzg = depth[1] - depth[0] +print(f"dxg = {dxg:.3f} m, dzg = {dzg:.3f} m <- deliberately not equal") + +def dist_to(x0): + """Distance to an electrode at (x0, 0, 0), floored at its own radius.""" + return np.maximum(np.sqrt((Xg - x0)**2 + Yg**2 + Zg**2), r_el) + +# Task 9 -- two blanks. This is Task 8 again, in different clothes. +# V: the formula above, source at x = +a_sep/2, sink at x = -a_sep/2. +# dist_to floors the distance at the electrode radius, so there is +# nothing to mask and nothing to nan_to_num. +# J: -grad(V)/rho. Pass dxg, dxg, dzg. On this grid z is spaced +# differently from x and y, and passing dxg three times costs 6.5% on +# the current measured in the next cell, enough to fail its check. + +V_dc = ___ +Jx, Jy, Jz = ___ + +# --- given: the survey, both panels on one colour scale and one colorbar --- +# plane="z" is the ground surface; plane="y" is the vertical section, where +# the in-plane components are (Jx, Jz), not (Jx, Jy). +vm = float(np.nanpercentile(np.abs(V_dc[:, :, 0]), 98)) +fig, axes = plt.subplots(2, 1, figsize=(7.2, 9.2)) +for ax_, comps, pl, ttl in ((axes[0], (Jx, Jy), "z", "a) ground surface, $z=0$"), + (axes[1], (Jx, Jz), "y", "b) vertical section, $y=0$")): + _, cf = fw.show_field_slice(Xg, Yg, Zg, *comps, background=V_dc, ax=ax_, + plane=pl, vmin=-vm, vmax=vm, colorbar=False, + density=1.2, title=ttl) +axes[1].invert_yaxis() # depth increases downwards +fig.colorbar(cf, ax=axes, label="$V$ [V]", fraction=0.05, pad=0.03) +plt.show() + +# --- self-check (leave this alone) --- +mid_dc = np.abs(Xg) < 1e-9 +fw.check("V is finite everywhere -- no holes in the model", + np.all(np.isfinite(V_dc)) and np.all(np.isfinite(Jx))) +fw.check("V = 0 on the mid-plane between the electrodes", + np.nanmax(np.abs(V_dc[mid_dc])) < 1e-6 * np.nanmax(np.abs(V_dc))) +fw.check("current flows from the source towards the sink at the surface", + np.nanmean(Jx[mid_dc]) < 0) +``` + +:::{admonition} Solution — Task 9 +:class: dropdown + +```python +V_dc = rho * I / (2*np.pi) * (1/dist_to(+a_sep/2) - 1/dist_to(-a_sep/2)) + +gVx, gVy, gVz = np.gradient(V_dc, dxg, dxg, dzg) +Jx, Jy, Jz = -gVx/rho, -gVy/rho, -gVz/rho +``` + +A presentation point worth reusing: `show_field_slice` returns `(ax, cf)`, so passing `colorbar=False` on both panels and handing the mappable `cf` to `fig.colorbar(..., ax=axes)` draws **one** bar beside the pair. Two bars carrying identical numbers are clutter, and they suggest to the reader that the scales differ. +::: + +Now use the field as an instrument. All the current injected at one electrode must cross any closed surface drawn around it, since there is nowhere else for it to go. Test that. + +```{code-cell} ipython3 +# The five faces of a box buried in the ground around one electrode. The top +# face is deliberately absent: it lies in the surface z = 0, where no current +# crosses into the air, so its contribution is zero by physics. +def buried_box_current(xc, hw=0.3): + i0 = int(np.argmin(np.abs(axis_g - (xc - hw)))) + i1 = int(np.argmin(np.abs(axis_g - (xc + hw)))) + j0 = int(np.argmin(np.abs(axis_g + hw))) + j1 = int(np.argmin(np.abs(axis_g - hw))) + k1 = int(np.argmin(np.abs(depth - hw))) + sx, sy, sz = slice(i0, i1+1), slice(j0, j1+1), slice(0, k1+1) + return (fw.area_integral(Jx[i1, sy, sz], dxg, dzg) - fw.area_integral(Jx[i0, sy, sz], dxg, dzg) + + fw.area_integral(Jy[sx, j1, sz], dxg, dzg) - fw.area_integral(Jy[sx, j0, sz], dxg, dzg) + + fw.area_integral(Jz[sx, sy, k1], dxg, dxg)) + +for xc, name in ((+a_sep/2, "source"), (-a_sep/2, "sink")): + print(f"current out of a box around the {name:6s}: {buried_box_current(xc):+7.4f} A") +print(f" injected: {I:+7.4f} A") + +# --- self-check (leave this alone) --- +fw.check_scalar("box around the source carries I", buried_box_current(+a_sep/2), I, rtol=0.01, unit=" A") +fw.check_scalar("box around the sink carries -I", buried_box_current(-a_sep/2), -I, rtol=0.01, unit=" A") +``` + +:::{admonition} Why five faces and not six? +:class: important + +The box is closed by the ground surface itself. Air does not conduct, so $J_z = 0$ at $z=0$. This is a **boundary condition**, true by physics, and not a quantity to be measured. + +Measuring it anyway is instructive. `np.gradient` has no neighbour above $z=0$, so it falls back to a one-sided difference and reports a spurious $J_z$ averaging $+0.25$ A/m² over the top of the box, apparently current entering from the air. The outward normal on that face is $-\hat{\boldsymbol{z}}$, so the face enters the sum as $-0.088$ A and reduces the box total from $1.003$ A to $0.915$ A, an **8.5% error** on a result that is otherwise accurate to 0.3%. + +The rule generalises well beyond this lab: **impose a boundary condition you know exactly, rather than asking a finite-difference stencil to recover it.** Numerical derivatives are least reliable where the domain stops. +::: + +--- + +:::{admonition} End of Lab 1 +:class: note + +Parts 1–4 cover the gradient. **The divergence and the curl continue in Lab 2**, which is lectured next. +::: diff --git a/book/1_gradient_divergence_curl/labs/week02_div_curl.md b/book/1_gradient_divergence_curl/labs/week02_div_curl.md new file mode 100644 index 0000000..1e28d5f --- /dev/null +++ b/book/1_gradient_divergence_curl/labs/week02_div_curl.md @@ -0,0 +1,826 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 +kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +mystnb: + # Workbook page: the task cells contain `___` blanks by design, so it must + # not be executed at build time. Readers run it themselves with Live Code. + execution_mode: 'off' +--- + +# Lab 2: Divergence and Curl + +:::{admonition} Computer lab +:class: note + +The second of two labs on the operators of this chapter, following Lab 1 on series and the gradient. Each task states a physical question, gives the steps, and ends with a self-check you can run. Plotting is supplied in the module `fwtools`, so that your effort goes into the physics rather than into rendering transparent isosurfaces. +::: + +## Learning objectives + +By the end of this lab you should be able to: + +- **Distinguish diverging arrows from non-zero divergence.** Compute $\nabla\cdot\boldsymbol{v}$, justify the result by flux rather than by algebra, and identify the only radial flow that is incompressible. +- **Use the divergence theorem as a measurement.** Verify $\oint_S\boldsymbol{v}\cdot\hat{\boldsymbol{n}}\,dS = \int_{\mathcal{D}} \nabla\cdot\boldsymbol{v}\,dV$ numerically, and account for what happens when the source shrinks to a point. + +--- + +## Part 0 — Setup + +Run this once. It contains no physics: it fetches two packages the browser lacks, locates `fwtools`, and defines the Coulomb constant. + +```{code-cell} ipython3 +# No physics above the k_e = ... line near the bottom. +import sys, pathlib + +import numpy as np +import matplotlib.pyplot as plt +from scipy.constants import epsilon_0 + +# --- Live Code housekeeping, not part of the physics ----------------------- +try: + import plotly.io as pio +except ModuleNotFoundError: + print("Fetching plotly. A few seconds, and only the first time...") + import micropip + await micropip.install("plotly") + import plotly.io as pio + +try: + import nbformat # noqa: F401 +except ModuleNotFoundError: + import micropip, types + try: + await micropip.install("nbformat") + except Exception: + _nb = types.ModuleType("nbformat") + _nb.__version__ = "5.10.4" + sys.modules["nbformat"] = _nb + +for _p in (".", "book/1_gradient_divergence_curl/labs"): + if (pathlib.Path(_p) / "fwtools.py").exists(): + sys.path.insert(0, _p) + break +try: + import fwtools as fw +except ModuleNotFoundError: + from pyodide.http import pyfetch + _r = await pyfetch("fwtools.py") + pathlib.Path("fwtools.py").write_bytes(await _r.bytes()) + import fwtools as fw + +pio.renderers.default = "plotly_mimetype+notebook" +# --------------------------------------------------------------------------- + +k_e = 1.0 / (4.0 * np.pi * epsilon_0) # Coulomb constant, 8.99e9 V*m/C +Q = 1e-9 # 1 nC test charge + +print(f"epsilon_0 = {epsilon_0:.4e} F/m") +print(f"k_e = {k_e:.4e} V*m/C") +``` + +### Carried over from Lab 1 + +The same cube of sample points, and the fields Lab 1 built on it. Nothing here is an +exercise: these are Lab 1's answers, given so that this notebook runs on its own. + +```{code-cell} ipython3 +n, L = 61, 2.0 # odd n, so the origin is a sample point +axis = np.linspace(-L, L, n) # one axis, shared by x, y and z +X, Y, Z = np.meshgrid(axis, axis, axis, indexing="ij") +dx = dy = dz = axis[1] - axis[0] + +c = n // 2 # index of the origin +# Mask reused by the self-checks. `interior` drops the two outermost cells, +# so comparisons exclude the six faces of the box, where sampling is worst +# and np.gradient has only one-sided neighbours. +interior = np.zeros(X.shape, dtype=bool) +interior[2:-2, 2:-2, 2:-2] = True + +print(f"grid shape {X.shape}, spacing {dx:.4f} m, {X.size:,} sample points") +print(f"X[i,j,k] = x[i] -> X[-1, 0, 0] = {X[-1, 0, 0]:.1f} m") +``` + +```{code-cell} ipython3 +# Lab 1, Tasks 3, 4, 6 and 7 -- given here, not set again. +def distance_to(X, Y, Z, x0=0.0, y0=0.0, z0=0.0): + return np.sqrt((X - x0)**2 + (Y - y0)**2 + (Z - z0)**2) + +r = distance_to(X, Y, Z) # distance from the origin +rs = np.maximum(r, 1e-12) # 0/0 at the source is not a lesson +rhx, rhy, rhz = X / rs, Y / rs, Z / rs # the outward unit radial vector + +r_masked = np.where(r < 0.25, np.nan, r) # the singularity kept off the grid +V = k_e * Q / r_masked # potential of the 1 nC point charge +_dVx, _dVy, _dVz = np.gradient(V, dx, dy, dz) +Ex, Ey, Ez = -_dVx, -_dVy, -_dVz # E = -grad V + +print(f"grid {X.shape}, spacing {dx:.4f} m") +print(f"|E| at (1,0,0) = {np.sqrt(Ex**2+Ey**2+Ez**2)[-1-15, c, c]:.3f} V/m") +``` + +--- + +## Part 1 — Divergence + +The gradient takes a scalar and returns a vector. The divergence takes a vector field and returns a scalar: + +$$ \nabla\cdot\boldsymbol{A} \;=\; \lim_{\Delta V \to 0}\frac{1}{\Delta V}\oint_S \boldsymbol{A}\cdot\hat{\boldsymbol{n}}\,dS \;=\; \frac{\partial A_x}{\partial x} + \frac{\partial A_y}{\partial y} + \frac{\partial A_z}{\partial z} $$ + +Read the definition on the left rather than the formula on the right: **treat $\boldsymbol{A}$ as a fluid velocity**, place a small box anywhere, and measure the net outflow through its walls per unit volume. + +| $\nabla\cdot\boldsymbol{A}$ | Name | Picture | +| :---: | :--- | :--- | +| $> 0$ | **source** | a tap: more leaves than arrives | +| $< 0$ | **sink** | a drain: more arrives than leaves | +| $= 0$ | **solenoidal** | whatever flows in, flows out | + +### Task 1 — the operator, and its independence of the origin + +The operator is three lines, and they are given. One derivative along one axis per component: `np.gradient(Ax, dx, axis=0)` returns $\partial A_x/\partial x$ and nothing else, whereas asking for all three and discarding two costs three times the memory. The cross terms are not part of a divergence. + +**The question is the one raised by the definition.** Flux per unit volume is measured around a point, so does the result depend on which point is called the origin? Take the outward flow $\boldsymbol{A} = \boldsymbol{r}$, whose divergence follows on paper as $1+1+1 = 3$, then shift the whole field so that it streams out of $(0.8, -0.4, 0.3)$. Predict the divergence before computing it. + +```{code-cell} ipython3 +# --- given --- +def divergence(Ax, Ay, Az, dx, dy, dz): + return (np.gradient(Ax, dx, axis=0) + + np.gradient(Ay, dy, axis=1) + + np.gradient(Az, dz, axis=2)) + +# Task 1 -- two blanks. The same outward flow, seen from somewhere else. +x0, y0, z0 = 0.8, -0.4, 0.3 +Sx, Sy, Sz = ___ # the field r - r0, as three arrays +div_shifted = ___ # its divergence + +# --- self-check (leave this alone) --- +fw.check_close("div of the position vector = 3", + divergence(X, Y, Z, dx, dy, dz), 3.0, rtol=1e-6) +fw.check_close("...and 3 again when the source is moved", + div_shifted, 3.0, rtol=1e-6) +fw.check("the shifted field really is different from the original", + not np.allclose(Sx, X)) +``` + +:::{admonition} Solution — Task 1 +:class: dropdown + +```python +Sx, Sy, Sz = X - x0, Y - y0, Z - z0 +div_shifted = divergence(Sx, Sy, Sz, dx, dy, dz) +``` +::: + +:::{admonition} Why the answer had to be 3 either way +:class: tip + +Moving the source changed every arrow in the box and changed the divergence nowhere. Differentiation removes the constant: $\partial(x - x_0)/\partial x = 1$ for any $x_0$. + +The divergence is a **local** quantity: it is built from a limit taken around one point, so it depends on the field in a shrinking neighbourhood of that point and not on where the axes were placed. Every operator in this course has that property, and it is what makes $\nabla\cdot\boldsymbol{E} = \rho_v/\varepsilon_0$ a statement about places rather than about coordinate systems. +::: + +### Task 2 — the only incompressible radial flow + +Water of constant density flows outward from a source at the origin. Away from that source nothing is created or destroyed, so the flow is **incompressible**: + +$$ \nabla\cdot\boldsymbol{v} = 0 \qquad \text{for } r \neq 0. $$ + +Constant density and a point source force the flow to be radial, $\boldsymbol{v} = f(r)\,\boldsymbol{r}$, and incompressibility then pins $f$ down completely: + +$$ \nabla\cdot\boldsymbol{v} = 3f(r) + r\frac{df}{dr} = 0 \qquad\Longrightarrow\qquad f(r) = \frac{A}{r^{3}}. $$ + +Rather than assume this, test four candidates and let the divergence select. + +```{code-cell} ipython3 +# The measure reported by the loop below: +# +# |div v| / (|v| / r), median over the test band +# +# |v|/r is the natural size of a derivative of v, so the ratio is a pure +# number: 1 means "as large as a derivative of this field could be". + +r_safe = np.where(r < 0.3, np.nan, r) +band_i = interior & (r > 0.6) & (r < 1.6) + +# Task 2 -- three blanks, inside the loop. +results = {} +for name, f_r in [("const", np.ones_like(r_safe)), + ("1/r^2", 1/r_safe**2), + ("1/r^3", 1/r_safe**3), + ("1/r^4", 1/r_safe**4)]: + vx, vy, vz = ___ # v = f(r) * (X, Y, Z): three arrays + dv = ___ # its divergence (nan_to_num each part) + scale = ___ # |v|/r AT THE BAND POINTS -- index it + # with [band_i], so it comes out 1-D + # and the same length as dv[band_i] + + # --- given --- + results[name] = np.nanmedian(np.abs(dv[band_i]) / scale) + print(f" f = {name:6s}: median |div v| / (|v|/r) = {results[name]:8.2%}") + +# --- self-check (leave this alone) --- +fw.check(f"scale is one value per band point ({np.shape(scale)} vs " + f"{np.shape(dv[band_i])})", np.shape(scale) == np.shape(dv[band_i]), + "index it with [band_i] -- a whole-grid array or a single median " + "both change the statistic being reported") +fw.check(f"1/r^3 is the divergence-free one ({results['1/r^3']:.2%})", + results["1/r^3"] < 0.05) +fw.check("...and the other three are not", + min(results[k] for k in ("const", "1/r^2", "1/r^4")) > 0.5) +fw.check(f"f = const reproduces Task 1's div(r) = 3 ({results['const']:.2%})", + np.isclose(results["const"], 3.0, rtol=1e-3)) +``` + +:::{admonition} Solution — Task 2 +:class: dropdown + +```python + vx, vy, vz = f_r*X, f_r*Y, f_r*Z + dv = divergence(*(np.nan_to_num(q) for q in (vx, vy, vz)), dx, dy, dz) + scale = (np.sqrt(vx**2 + vy**2 + vz**2) / r_safe)[band_i] +``` +::: + +:::{admonition} Where the inverse-square law comes from +:class: important + +One candidate gives 300%, two give almost exactly 100%, and one gives 0.66%. Only $f = A/r^{3}$ survives, as the algebra predicts. + +The 300% is not an accident. For $f = \text{const}$ the field is the position vector, $\boldsymbol{v} = \boldsymbol{r}$, whose divergence Task 1 measured as exactly 3, while $\lvert\boldsymbol{v}\rvert/r = 1$, so the ratio must be 3. The surviving case rewrites as + +$$ \boldsymbol{v} = \frac{A}{r^{3}}\boldsymbol{r} = \frac{A}{r^{2}}\,\hat{\boldsymbol{r}}. $$ + +**This is the same $1/r^{2}$ used since Lab 1's Task 6.** Here it was not assumed and no charge was mentioned; it follows from conservation away from the source together with the three-dimensionality of space. The surface of a sphere grows as $r^{2}$, so a fixed flux crossing it must thin as $1/r^{2}$. + +Coulomb's law, Newtonian gravity and this flow share an exponent for that one geometric reason. +::: + +### Task 2, continued — a field with no source anywhere + +Note the restriction on that result: $\nabla\cdot\boldsymbol{v} = 0$ **for $r \neq 0$**. The origin must be excluded, because that is where the water is injected; a closed surface around it would find the tap. + +The next field admits no such exception. To first order the Earth's magnetic field is a **dipole**: a north and a south pole so close together that they coincide. With dipole moment $\boldsymbol{m}$, + +$$ \boldsymbol{B} = \frac{3\boldsymbol{r}\,(\boldsymbol{r}\cdot\boldsymbol{m}) - r^{2}\boldsymbol{m}}{r^{5}}. $$ + +Take $\boldsymbol{m} = \hat{\boldsymbol{z}}$ on the cube set up above, where $z$ points up, and measure the divergence with the same function. + +The Earth's own moment points roughly geographic south, which is why the magnetic pole in the Arctic is magnetically a **south** pole and attracts the north end of a compass needle. Reversing $\boldsymbol{m}$ reverses every arrow below and leaves $\nabla\cdot\boldsymbol{B}$ unchanged. + +```{code-cell} ipython3 +# Task 2, continued -- fill in the three components. +# With m = z-hat, the dot product r . m is simply Z. +# Careful with the second term: it appears only in the z-component. + +r_dot_m = Z +Bx = ___ +By = ___ +Bz = ___ + +div_B = divergence(np.nan_to_num(Bx), np.nan_to_num(By), np.nan_to_num(Bz), dx, dy, dz) + +# --- given: the same scale-free measure as above --- +B_mag = np.sqrt(Bx**2 + By**2 + Bz**2) +print(f" dipole B : median |div B| / (|B|/r) = " + f"{np.nanmedian(np.abs(div_B[band_i]) / (B_mag/r_safe)[band_i]):8.2%}") + +# --- self-check (leave this alone) --- +fw.check("B is divergence-free", + np.nanmedian(np.abs(div_B[band_i]) / (B_mag/r_safe)[band_i]) < 0.05) +fw.check("B is not simply radial (it has a north and a south)", + np.nanmin((Bx*X + By*Y + Bz*Z)[band_i]) < 0) +``` + +:::{admonition} Solution — Task 2, continued +:class: dropdown + +```python +Bx = 3*X*r_dot_m / r_safe**5 +By = 3*Y*r_dot_m / r_safe**5 +Bz = (3*Z*r_dot_m - r_safe**2) / r_safe**5 +``` +::: + +:::{admonition} No magnetic monopoles +:class: important + +Both fields are divergence-free over the region measured, but the two statements differ. + +The flow required an exclusion: $\nabla\cdot\boldsymbol{v} = 0$ away from the origin, because the origin is a tap. The dipole requires none, and $\nabla\cdot\boldsymbol{B} = 0$ holds **everywhere in space, including at the source**. No point can be excluded to reveal a magnet leaking field the way the tap leaks water. This is one of Maxwell's equations: magnetic monopoles do not exist, and field lines of $\boldsymbol{B}$ never begin or end but close on themselves. + +Two remarks on the numbers. Both cells report the same scale-free measure, so the results are directly comparable. The dipole's 1.8% is worse than the radial flow's 0.66%, not because the physics is less secure but because $\boldsymbol{B}$ falls off as $1/r^{3}$ rather than $1/r^{2}$, leaving a centred difference more curvature to miss. Part 2 tests the same claim far below 2% by putting a closed surface around the dipole instead of differentiating it. + +The second check is also informative: $\boldsymbol{B}\cdot\boldsymbol{r}$ is negative somewhere, whereas the outward flow of Task 2 is never negative. The dipole points inward over part of space; it returns. That is the numerical signature of a field closing on itself. +::: + +### Task 3 — three flows + +Three velocity fields. For each one: **sketch it, predict the sign of the divergence, then measure.** Record the predictions first; the task is about the gap between intuition and the result. + +| | Field $\boldsymbol{A}$ | What it looks like | +| :---: | :--- | :--- | +| **(a)** | $x\,\hat{\boldsymbol{x}} + y\,\hat{\boldsymbol{y}} + z\,\hat{\boldsymbol{z}}$ | outward flow in all directions | +| **(b)** | $-y\,\hat{\boldsymbol{x}} + x\,\hat{\boldsymbol{y}}$ | fluid rotating about the $z$-axis | +| **(c)** | $x\,\hat{\boldsymbol{x}} - y\,\hat{\boldsymbol{y}}$ | stretching along $x$, squeezing along $y$ | + +```{code-cell} ipython3 +# Record the predictions BEFORE running the next cell: +1 for a source, +# -1 for a sink, 0 for solenoidal. The next cell scores them. +predictions = {"a": ___, "b": ___, "c": ___} +``` + +```{code-cell} ipython3 +# Task 3 -- six blanks: three fields, three divergences. +zero = np.zeros_like(X) +Aa = ___ # (a) outward flow, as a triple +Ab = ___ # (b) rotation about z +Ac = ___ # (c) stretch in x, squeeze in y + +div_a = ___ +div_b = ___ +div_c = ___ + +# --- given: the three side by side, one shared scale, one colorbar --- +for name, d in [("(a) outward flow", div_a), ("(b) rotation", div_b), + ("(c) shear", div_c)]: + print(f"{name:20s} div = {d.mean():+.3f}") + +fig, axes = plt.subplots(1, 3, figsize=(16, 4.6)) +for ax_, (name, A, d) in zip(axes, [("(a) outward flow", Aa, div_a), + ("(b) rotation", Ab, div_b), + ("(c) shear flow", Ac, div_c)]): + fw.show_field_slice(X, Y, Z, *A[:2], background=d, ax=ax_, density=1.1, + vmin=-3, vmax=3, colorbar=(ax_ is axes[-1]), + label=r"$\nabla\cdot\mathbf{A}$ [s$^{-1}$]", title=name) +plt.tight_layout() +plt.show() +# Examine (b) and (c) before reading the note below: both come out a uniform +# zero, for entirely different reasons. + +# --- self-check (leave this alone) --- +# (a) has a non-zero answer, so a relative test works. (b) and (c) are exactly +# zero, and nothing can be measured relative to zero, so they get an absolute +# tolerance instead. +fw.check_close("(a) div = 3", div_a, 3.0, rtol=1e-6) +fw.check_abs("(b) div = 0 (rotation)", div_b, atol=1e-9) +fw.check_abs("(c) div = 0 (shear)", div_c, atol=1e-9) + +for key, measured in (("a", div_a), ("b", div_b), ("c", div_c)): + sign = int(np.sign(np.round(measured.mean(), 6))) + verdict = "as predicted" if predictions[key] == sign else "NOT what you predicted" + print(f" ({key}) you said {predictions[key]:+d}, measured {sign:+d} -- {verdict}") +``` + +:::{admonition} Solution — Task 3 +:class: dropdown + +```python +Aa = (X, Y, Z) +Ab = (-Y, X, zero) +Ac = (X, -Y, zero) + +div_a = divergence(*Aa, dx, dy, dz) +div_b = divergence(*Ab, dx, dy, dz) +div_c = divergence(*Ac, dx, dy, dz) +``` +::: + +:::{admonition} Field (c) is the trap +:class: warning + +Along the $x$-axis, field (c) flows outward and resembles a source. It is not: + +$$ \nabla\cdot\boldsymbol{A} = \frac{\partial}{\partial x}(x) + \frac{\partial}{\partial y}(-y) = 1 - 1 = 0 $$ + +Place a box at the origin: fluid leaves through the left and right walls and enters through the top and bottom at exactly the same rate. The parcel changes **shape**, not **volume**. + +Diverging arrows are not divergence. Outflow in one direction can be cancelled exactly by inflow in another. Task 5 puts a closed surface around this field and measures the cancellation directly. +::: + +### Task 4 — the divergence as a charge detector + +Gauss's law, for a field in vacuum, says + +$$ \nabla\cdot\boldsymbol{E} = \frac{\rho_v}{\varepsilon_0} $$ + +which is a strong claim: **the divergence of $\boldsymbol{E}$ at a point gives the charge density at that point and nothing else.** Where there is no charge, $\boldsymbol{E}$ is solenoidal, however widely its arrows spread. + +Test that pointwise, on a source a grid can hold. A point charge cannot serve: it has infinite density at one location. Take instead a charge **distributed over a finite blob**, which is what any real charged object is: + +$$ \rho_v(r) = \rho_{v0}\,e^{-r^{2}/a^{2}}, \qquad \rho_{v0} = 10^{-9}\ \text{C/m}^3, \qquad a = 0.5\ \text{m} $$ + +Here $a$ is the **width of the blob**. In Lab 1's Task 9 the same letter denoted an electrode separation, the second symbol these two labs overload, after $\rho$. The code keeps them apart as `a` here and `a_sep` there; in algebra only the context distinguishes them. + +Integrating over a sphere of radius $r$ gives the charge it encloses: + +$$ Q_{\text{enc}}(r) = \int_0^{r}\!\rho_v\,4\pi r'^{2}\,dr' = 4\pi\rho_{v0}\left[\frac{a^{3}\sqrt{\pi}}{4}\operatorname{erf}\!\left(\frac{r}{a}\right) - \frac{a^{2}r}{2}e^{-r^{2}/a^{2}}\right] $$ + +and Gauss's law, $E_r = Q_{\text{enc}}/4\pi\varepsilon_0r^{2}$, then gives the field, with the $4\pi$ cancelling: + +$$ E_r(r) = \frac{\rho_{v0}}{\varepsilon_0 r^{2}}\left[\frac{a^{3}\sqrt{\pi}}{4}\operatorname{erf}\!\left(\frac{r}{a}\right) - \frac{a^{2}r}{2}e^{-r^{2}/a^{2}}\right] $$ + +One check: near the centre $Q_{\text{enc}}$ grows as $r^{3}$ while the surface grows as $r^{2}$, so $E_r \to \rho_{v0} r/3\varepsilon_0$, zero at the centre, rising linearly, and peaking at $r \approx a$. + +```{code-cell} ipython3 +from scipy.special import erf + +a, rho_v0 = 0.5, 1e-9 + +# --- given: the charge density, and the field Gauss's law gives it --- +# The two bracketed terms nearly cancel for r << a, so the closed form loses +# accuracy below r ~ 1e-6 m. On this grid the only such sample is the origin, +# where the r-hat components are zero in any case. +rho_v = rho_v0 * np.exp(-r**2 / a**2) +E_r = rho_v0 / (epsilon_0 * rs**2) * ( + (a**3 * np.sqrt(np.pi) / 4) * erf(rs / a) - (a**2 * rs / 2) * np.exp(-rs**2 / a**2) +) + +# Task 4 -- two blanks. +# E_r is a radial MAGNITUDE. Give it a direction, then differentiate. +Ex_b, Ey_b, Ez_b = ___ # components along (rhx, rhy, rhz) +div_blob = ___ # your Task 1 operator + +# --- given: the two pictures, forced onto one scale so they are comparable --- +hi = float(np.nanmax(rho_v / epsilon_0)) +units = r"[V m$^{-2}$]" +fig, axes = plt.subplots(1, 2, figsize=(12, 4.4)) +fw.show_scalar_slice(X, Y, Z, div_blob, ax=axes[0], cmap="magma", label=units, + vmin=0, vmax=hi, title=r"measured $\nabla\cdot\mathbf{E}$") +fw.show_scalar_slice(X, Y, Z, rho_v / epsilon_0, ax=axes[1], cmap="magma", label=units, + vmin=0, vmax=hi, title=r"actual $\rho_v/\varepsilon_0$") +plt.tight_layout() +plt.show() + +print(f"peak of rho_v/eps0 : {np.nanmax(rho_v/epsilon_0):8.2f}") +print(f"peak of measured div: {np.nanmax(div_blob):8.2f}") + +# --- self-check (leave this alone) --- +peak = np.nanmax(rho_v / epsilon_0) +_e = np.abs(div_blob[interior] - (rho_v / epsilon_0)[interior]) / peak +cart_worst, cart_median = float(_e.max()), float(np.median(_e)) +fw.check(f"div E = rho_v/eps0 pointwise (worst {cart_worst:.2%} of peak)", + cart_worst < 0.05, "check the component construction Ex_b = E_r * rhx") +``` + +:::{admonition} Solution — Task 4 +:class: dropdown + +```python +Ex_b, Ey_b, Ez_b = E_r * rhx, E_r * rhy, E_r * rhz +div_blob = divergence(Ex_b, Ey_b, Ez_b, dx, dy, dz) +``` +::: + +:::{admonition} What the two panels show +:class: important + +The two panels show the same distribution. The location of the charge was never supplied to the code: a field was differentiated, and the charge distribution came back out. + +Note where the divergence vanishes: everywhere outside the blob, where the field is still large and still spreading. **Strong field, zero divergence**: the two quantities are unrelated. +::: + +### The same operator, a different formula + +Everything so far used the Cartesian formula, because `np.gradient` differentiates along array axes. The divergence is flux per unit volume, a physical quantity that cannot depend on the choice of axes. Only the formula changes: + +| | Gradient $\nabla T$ | Divergence $\nabla\cdot\boldsymbol{A}$ | +| :--- | :--- | :--- | +| Cartesian $(x,y,z)$ | $\dfrac{\partial T}{\partial x}\hat{\boldsymbol{x}} + \dfrac{\partial T}{\partial y}\hat{\boldsymbol{y}} + \dfrac{\partial T}{\partial z}\hat{\boldsymbol{z}}$ | $\dfrac{\partial A_x}{\partial x} + \dfrac{\partial A_y}{\partial y} + \dfrac{\partial A_z}{\partial z}$ | +| Cylindrical $(\varrho,\phi,z)$ | $\dfrac{\partial T}{\partial \varrho}\hat{\boldsymbol{\varrho}} + \dfrac{1}{\varrho}\dfrac{\partial T}{\partial \phi}\hat{\boldsymbol{\phi}} + \dfrac{\partial T}{\partial z}\hat{\boldsymbol{z}}$ | $\dfrac{1}{\varrho}\dfrac{\partial (\varrho v_\varrho)}{\partial \varrho} + \dfrac{1}{\varrho}\dfrac{\partial v_\phi}{\partial \phi} + \dfrac{\partial v_z}{\partial z}$ | +| Spherical $(r,\phi,\theta)$ | $\dfrac{\partial T}{\partial r}\hat{\boldsymbol{r}} + \dfrac{1}{r}\dfrac{\partial T}{\partial \theta}\hat{\boldsymbol{\theta}} + \dfrac{1}{r\sin\theta}\dfrac{\partial T}{\partial \phi}\hat{\boldsymbol{\phi}}$ | $\dfrac{1}{r^{2}}\dfrac{\partial (r^{2}v_r)}{\partial r} + \dfrac{1}{r\sin\theta}\dfrac{\partial (v_\theta \sin\theta)}{\partial \theta} + \dfrac{1}{r\sin\theta}\dfrac{\partial v_\phi}{\partial \phi}$ | + +Cylindrical $\varrho=\sqrt{x^2+y^2}$ is the distance from the $z$-axis; spherical $r=\sqrt{x^2+y^2+z^2}$, used throughout this lab, is the distance from the origin. They are written differently precisely to keep them apart. + +One reading note: the spherical coordinates are named $(r,\phi,\theta)$, but the terms in the row above are listed as $r$, then $\theta$, then $\phi$, the order in which the scale factors $(1,\ r,\ r\sin\theta)$ are derived. The order of terms in a sum is immaterial. + +Both fields built so far are spherically symmetric, $\boldsymbol{E} = E_r(r)\,\hat{\boldsymbol{r}}$ with no $\theta$ or $\phi$ dependence, so two of the three spherical terms vanish and the divergence reduces to one ordinary derivative along one line: + +$$ \nabla\cdot\boldsymbol{E} \;=\; \frac{1}{r^{2}}\frac{d}{dr}\!\left(r^{2}E_r\right) $$ + +```{code-cell} ipython3 +dr = 0.005 +r_line = np.arange(0.05, 2.0 + dr, dr) # one radial line, not a cube + +# the same two fields as before, as functions of r alone +E_R_blob = rho_v0 / (epsilon_0 * r_line**2) * ( + (a**3 * np.sqrt(np.pi) / 4) * erf(r_line / a) + - (a**2 * r_line / 2) * np.exp(-r_line**2 / a**2)) +E_r_point = k_e * Q / r_line**2 + +div_blob_sph = np.gradient(r_line**2 * E_R_blob, dr) / r_line**2 +div_point_sph = np.gradient(r_line**2 * E_r_point, dr) / r_line**2 + +rho_v_line = rho_v0 * np.exp(-r_line**2 / a**2) + +# --- given: the radial profile Task 4 asserted but never drew --- +Q_total = np.pi**1.5 * rho_v0 * a**3 # all of the blob's charge +plt.figure(figsize=(5.8, 4.2)) +plt.plot(r_line, E_R_blob, "k", lw=1.8, label="$E_r(r)$, exact") +plt.plot(r_line, rho_v0 * r_line / (3 * epsilon_0), "C1--", lw=1.2, + label=r"small $r$: $\rho_{v0}r/3\varepsilon_0$") +plt.plot(r_line, Q_total / (4 * np.pi * epsilon_0 * r_line**2), "C2:", lw=1.4, + label=r"large $r$: $Q/4\pi\varepsilon_0 r^2$") +plt.axvline(a, color="C0", lw=1, alpha=0.6) +plt.annotate("$r = a$", (a, 1.12 * E_R_blob.max()), color="C0", ha="left") +plt.xlabel("$r$ [m]"); plt.ylabel(r"$E_r$ [V m$^{-1}$]") +plt.ylim(0, 1.25 * E_R_blob.max()); plt.grid(alpha=0.3); plt.legend(fontsize=8) +plt.title("The blob's field: linear inside, inverse-square outside") +plt.show() + +err_sph = np.abs(div_blob_sph - rho_v_line / epsilon_0)[1:-1] / np.max(rho_v_line / epsilon_0) +print(f"blob : {r_line.size} samples on a line vs {X.size:,} in the cube") +print(f" worst error {err_sph.max():.3%} of peak, median {np.median(err_sph):.4%}") +print(f" Cartesian, from Task 4: {cart_worst:.3%} and {cart_median:.4%}") +print(f"point: r^2 E_r varies by {np.ptp(r_line**2 * E_r_point):.1e} over the whole line") +print(f" max |div E| = {np.abs(div_point_sph).max():.1e} (round-off, not physics)") +``` + +:::{admonition} Why curvilinear coordinates are worth the trouble +:class: important + +Same field, same operator, same answer, obtained from a few hundred samples on a line rather than a quarter of a million in a cube, and several times more accurately. + +For the point charge the gain is certainty rather than accuracy. $r^{2}E_r = Q/4\pi\varepsilon_0$ is a **constant**, so its derivative is analytically zero for every $r>0$: not 1% of something, but zero, in one line of algebra. What the cell prints is the precision with which double arithmetic subtracts two equal numbers, around $10^{-13}$, or exactly $0$ when the cancellation is exact. Changing `dr` moves that last digit; it does not move the algebra. Cartesian coordinates could establish only that the divergence is small. + +Matching the coordinates to the symmetry of the source replaces three noisy numerical derivatives with one line of algebra. That is the purpose of the second and third rows of the table. +::: + +--- + +## Part 2 — Flux, and the divergence theorem + +Part 1 used the differential form of Gauss's law, which compares two numbers at one point. The integral form relates a volume to the surface enclosing it: + +$$ \oint_S \boldsymbol{E}\cdot\hat{\boldsymbol{n}}\,dS \;=\; \int_{\mathcal{D}} \nabla\cdot\boldsymbol{E}\;dV \;=\; \frac{Q_{\text{enc}}}{\varepsilon_0} $$ + +with $S$ the closed surface, $\hat{\boldsymbol{n}}$ its outward unit normal, and $\mathcal{D}$ the volume it encloses. + +The first equality is the **divergence theorem**, pure vector calculus, valid for any well-behaved field. The second is the physics. Together they state that measuring $\boldsymbol{E}$ on a closed surface gives the charge inside, and nothing about its arrangement or about any charge outside. + +Take $S$ to be a cube of half-width $h$ centred on the origin, faces on grid planes. On the $+x$ face the outward normal is $+\hat{\boldsymbol{x}}$, so it contributes $\int\!\!\int E_x\,dy\,dz$; on the $-x$ face the normal is $-\hat{\boldsymbol{x}}$ and the same integral enters negatively. Six faces, three pairs. + +### Task 5 — close the surface + +```{code-cell} ipython3 +# `fw.area_integral(F2, da, db)` integrates a 2-D array over the face it +# spans; `fw.volume_integral(F3, dx, dy, dz)` does the same over a box. +# `fw.box_indices(X, h)` gives the index range of the cube |x|,|y|,|z| <= h. +# +# The x pair is written for you; the pattern is one row per axis: +# +# face pair outward samples inward samples spacings +# x Ax[i1, s, s] Ax[i0, s, s] dy, dz +# y Ay[s, i1, s] Ay[s, i0, s] dx, dz +# z Az[s, s, i1] Az[s, s, i0] dx, dy +# +# The axis you pin to i0/i1 is the axis whose spacing you leave out. +# NOTE: this closes over X, dx, dy, dz from the cell above, so it is tied to +# this grid and is not a general-purpose function. + +def closed_box_flux(Ax, Ay, Az, half_width): + """Net outward flux through the cube |x|,|y|,|z| <= half_width.""" + i0, i1 = fw.box_indices(X, half_width) + s = slice(i0, i1 + 1) + flux_x = (fw.area_integral(Ax[i1, s, s], dy, dz) + - fw.area_integral(Ax[i0, s, s], dy, dz)) + flux_y = ___ + flux_z = ___ + return flux_x + flux_y + flux_z + + +# --- given: three routes to the same number, and the Task 3 arbiter --- +# Finish closed_box_flux above; everything below is written for you. +flux_1m = closed_box_flux(Ex_b, Ey_b, Ez_b, 1.0) + +print(f"{'h [m]':>6} {'surface':>12} {'volume':>12} {'Q_enc/eps0':>12}") +for h in (0.6, 1.0, 1.4): + i0, i1 = fw.box_indices(X, h) + s_ = slice(i0, i1 + 1) + surf = closed_box_flux(Ex_b, Ey_b, Ez_b, h) + vol = fw.volume_integral(div_blob[s_, s_, s_], dx, dy, dz) + qenc = fw.volume_integral(rho_v[s_, s_, s_], dx, dy, dz) / epsilon_0 + print(f"{h:6.1f} {surf:12.3f} {vol:12.3f} {qenc:12.3f}") + +# Task 3 settled by measurement rather than by argument. Both (b) and (c) +# appear to throw fluid outwards somewhere; a closed surface is the arbiter, +# and it differentiates nothing. +print(f"\nflux of (b), the rotation : {closed_box_flux(-Y, X, zero, 1.0):+.2e}") +print(f"flux of (c), the shear : {closed_box_flux(X, -Y, zero, 1.0):+.2e}") + +# --- self-check (leave this alone) --- +i0, i1 = fw.box_indices(X, 1.0) +s = slice(i0, i1 + 1) +fw.check_scalar("closed-surface flux = Q_enc/eps0", flux_1m, + fw.volume_integral(rho_v[s, s, s], dx, dy, dz) / epsilon_0, + rtol=0.01, unit=" V*m") +fw.check_scalar("divergence theorem: surface = volume", flux_1m, + fw.volume_integral(div_blob[s, s, s], dx, dy, dz), + rtol=0.01, unit=" V*m") +``` + +:::{admonition} Solution — Task 5 +:class: dropdown + +```python + flux_y = (fw.area_integral(Ay[s, i1, s], dx, dz) + - fw.area_integral(Ay[s, i0, s], dx, dz)) + flux_z = (fw.area_integral(Az[s, s, i1], dx, dy) + - fw.area_integral(Az[s, s, i0], dx, dy)) + return flux_x + flux_y + flux_z +``` +::: + +:::{admonition} Three routes, one number +:class: important + +Three independent calculations. The first never examines the interior of the box, the second never examines the surface, and the third never examines the field. They agree to a fraction of a percent. + +The result grows with $h$ and then stops: once the cube holds nearly all the charge, enlarging it adds surface but no charge. Charge outside a closed surface contributes exactly nothing, because the field lines it sends in through one wall leave through another. +::: + +### Shrinking the source to a point + +Run the same surface integral on the point-charge field of Lab 1's Task 7, whose divergence could not be measured at the origin because the singularity had to be masked. + +Rearranged, Gauss's law turns the flux into a **charge meter**: $Q_{\text{enc}} = \varepsilon_0 \oint_S \boldsymbol{E}\cdot\hat{\boldsymbol{n}}\,dS$. Weigh the charge inside each box in coulombs and compare it with the 1 nC placed there. + +```{code-cell} ipython3 +print("box half-width charge it finds") +for h in (0.6, 1.0, 1.4): + Q_found = epsilon_0 * closed_box_flux(Ex, Ey, Ez, h) + print(f" {h:.1f} m {Q_found * 1e12:8.2f} pC") +print(f"\n actually there {Q * 1e12:8.2f} pC") + +# The shell between the 0.6 m and 1.4 m boxes holds no charge. Weigh it: what +# enters the small box must leave the large one, so the difference of the two +# fluxes is the charge in between. +Q_shell = epsilon_0 * (closed_box_flux(Ex, Ey, Ez, 1.4) + - closed_box_flux(Ex, Ey, Ez, 0.6)) +print(f"\ncharge in the shell between them: {Q_shell * 1e12:+.2f} pC " + f"({abs(Q_shell) / Q:.2%} of the charge at the centre)") +``` + +:::{admonition} Where did the charge go? +:class: important + +Every box weighs the same 1 nC to a fraction of a percent, and the shell between two of them weighs nothing. All the charge lies in the only region common to every box: the origin. + +The whole source therefore sits at one point, where $\nabla\cdot\boldsymbol{E}$ is not a large number but undefined: $\rho_v$ has become a **Dirac delta**, zero everywhere, infinite at one point, with finite integral $Q$. The integral form survives exactly where the differential form fails. + +The same statement for magnetism carries no source term at all: + +$$ \nabla\cdot\boldsymbol{B} = 0 \qquad\Longleftrightarrow\qquad \oint_S \boldsymbol{B}\cdot\hat{\boldsymbol{n}}\,dS = 0 \ \ \text{for every closed } S $$ + +The measurement returns zero around any closed surface anywhere: there are no magnetic monopoles, and field lines of $\boldsymbol{B}$ never begin or end. +::: + +### The dipole, exactly + +Task 2 measured $\nabla\cdot\boldsymbol{B} = 0$ for the Earth's dipole and returned 1.8%, which is grid error rather than physics. The same claim can be tested without differentiating: put a closed surface around the dipole and weigh what crosses it. + +One warning before reading the numbers. A box centred on the origin is too easy a test for this dipole: with $\boldsymbol{m} = \hat{\boldsymbol{z}}$, $B_x$ and $B_y$ are odd in $z$ and $B_z$ is even, so on a $z$-symmetric box the faces cancel in pairs before any physics enters. An off-centre box is the honest test, and the cell below runs both. + +```{code-cell} ipython3 +r_dot_m = Z +Bx = 3*X*r_dot_m / r_safe**5 +By = 3*Y*r_dot_m / r_safe**5 +Bz = (3*Z*r_dot_m - r_safe**2) / r_safe**5 + +B = tuple(np.nan_to_num(q) for q in (Bx, By, Bz)) +v = tuple(np.nan_to_num(q / r_safe**3) for q in (X, Y, Z)) + +# --- given: the same surface integral over any grid-aligned box, centred +# on the origin or not. Same six faces, same three pairs as Task 5. +def box_flux(A, x0, x1, y0, y1, z0, z1): + i = [int(np.argmin(np.abs(axis - q))) for q in (x0, x1, y0, y1, z0, z1)] + sx, sy, sz = slice(i[0], i[1]+1), slice(i[2], i[3]+1), slice(i[4], i[5]+1) + return (fw.area_integral(A[0][i[1], sy, sz], dy, dz) - fw.area_integral(A[0][i[0], sy, sz], dy, dz) + + fw.area_integral(A[1][sx, i[3], sz], dx, dz) - fw.area_integral(A[1][sx, i[2], sz], dx, dz) + + fw.area_integral(A[2][sx, sy, i[5]], dx, dy) - fw.area_integral(A[2][sx, sy, i[4]], dx, dy)) + +boxes = [("centred, h = 0.6", (-0.6, 0.6, -0.6, 0.6, -0.6, 0.6)), + ("centred, h = 1.0", (-1.0, 1.0, -1.0, 1.0, -1.0, 1.0)), + ("centred, h = 1.4", (-1.4, 1.4, -1.4, 1.4, -1.4, 1.4)), + ("lopsided in z ", (-1.0, 1.0, -1.0, 1.0, -0.6, 1.0)), + ("lopsided in x, z", (-0.6, 1.0, -1.0, 1.0, -0.6, 1.0))] + +print(" box flux of B flux of the radial flow v") +for name, lim in boxes: + print(f" {name} {box_flux(B, *lim):+11.2e} {box_flux(v, *lim):+12.4f}") +print(f"\n 4*pi = {4*np.pi:.4f}; the integrator misses it by " + f"{4*np.pi - box_flux(v, -1, 1, -1, 1, -1, 1):.1e} on the flow") + +# --- self-check (leave this alone) --- +fw.check("the dipole encloses nothing -- even in a box that is not centred on it", + max(abs(box_flux(B, *lim)) for _, lim in boxes) < 1e-2) +fw.check("...and the same integrator does find the tap in the radial flow", + abs(box_flux(v, -1, 1, -1, 1, -1, 1) - 4*np.pi) < 0.01 * 4*np.pi) +``` + +:::{admonition} Two kinds of "divergence-free" +:class: important + +The radial flow returns $4\pi$ through every surface, whatever its size: there is a tap at the origin, and every box finds the same one, as every box found the same 1 nC above. + +The dipole returns **nothing** through any of them. On the three centred boxes the result is zero to machine precision, but the warning above applies: those boxes cancel the field against itself by symmetry and could return nothing else. The off-centre boxes are the measurement that counts, and they return $-2.5\times10^{-3}$ and $-2.2\times10^{-4}$. Compare the adjacent column: the same integrator, on the same grid, misses $4\pi$ by $6.8\times10^{-3}$ on the radial flow. **The flux of the dipole is zero to better than the accuracy this method achieves on anything.** + +The two divergence-free fields are therefore different statements. The flow has a tap that can be located by shrinking a surface onto it; the dipole has nothing to locate, at any size or placement of the surface. This is $\nabla\cdot\boldsymbol{B} = 0$ in the form that admits no exception, and it is why the integral form is worth constructing: it settles the question at the source, where the differential form had to be masked. +::: + +### Where do the 1% errors come from? + +Every derivative on this page is a centred difference, accurate to $O(\Delta x^{2})$: halving the spacing should reduce the error by four. Confirm it. The study is a single loop. + +```{code-cell} ipython3 +print(f"{'n':>4} {'dx [m]':>8} {'worst error':>12} {'ratio':>7}") +prev = None +for n_test in (21, 31, 41, 61): + ax_t = np.linspace(-L, L, n_test) + h_t = ax_t[1] - ax_t[0] + Xt, Yt, Zt = np.meshgrid(ax_t, ax_t, ax_t, indexing="ij") + rt = np.sqrt(Xt**2 + Yt**2 + Zt**2) + Rst = np.maximum(rt, 1e-12) + rho_t = rho_v0 * np.exp(-rt**2 / a**2) + E_Rt = rho_v0 / (epsilon_0 * Rst**2) * ( + (a**3 * np.sqrt(np.pi) / 4) * erf(Rst / a) + - (a**2 * Rst / 2) * np.exp(-Rst**2 / a**2)) + dv = divergence(E_Rt * Xt / Rst, E_Rt * Yt / Rst, E_Rt * Zt / Rst, h_t, h_t, h_t) + inner = np.zeros(Xt.shape, bool) + inner[2:-2, 2:-2, 2:-2] = True + e = np.nanmax(np.abs(dv[inner] - (rho_t / epsilon_0)[inner])) / np.nanmax(rho_t / epsilon_0) + ratio = "-" if prev is None else f"{prev / e:.2f}" + print(f"{n_test:>4} {h_t:>8.4f} {e:>11.2%} {ratio:>7}") + prev = e +``` + +:::{admonition} Second order, by measurement +:class: important + +Compare each ratio with the square of the spacing ratio: $1.5^2 = 2.25$ from $n=21$ to $31$, $1.33^2 = 1.78$ from $31$ to $41$, and $1.5^2 = 2.25$ from $41$ to $61$. + +The 1.06% in Task 4 is therefore not noise to be tolerated but a predictable quantity that can be reduced at a known cost, and the choice of $n = 61$ in Lab 1 can now be audited rather than assumed. +::: + +--- + +## Part 3 — Curl + +Return to field **(b)**, the rotation. Its divergence is zero everywhere, so by that measure it is indistinguishable from a field doing nothing. It nevertheless circulates, and every streamline closes on itself. + +The divergence cannot detect circulation. The operator that can is the **curl**, the third of the three operators this chapter is named after. + +:::{admonition} Exercises to follow +:class: note + +The computer exercises for the curl are not drafted yet. They will build on the circulation +integral and Stokes' theorem, using field **(b)** of Task 3 as the first test case. +::: + +--- + +## Closing + +The chain built in this lab, in one line: + +$$ \rho_v \;\longrightarrow\; V \;\xrightarrow{\ -\nabla\ }\; \boldsymbol{E} \;\xrightarrow{\ \nabla\cdot\ }\; \rho_v/\varepsilon_0 $$ + +- **Gradient.** Scalar in, vector out. Points along steepest increase, normal to the level surfaces, with length equal to the rate of increase. +- **Divergence.** Vector in, scalar out. Net flux per unit volume, which measures what is created at a point and nothing else. + +### The same two operators, elsewhere in ECT + +Electrostatics is a convenient place to learn this pair, not the only place to use it. Each row below gives a potential, its gradient, and a statement about sources. The numerical machinery written in this lab applies unchanged to all of them: + +| System | Potential | Field | Source equation | +| :--- | :--- | :--- | :--- | +| Electrostatics | $V$ [V] | $\boldsymbol{E} = -\nabla V$   [V/m] | $\nabla\cdot\boldsymbol{E} = \rho_v/\varepsilon_0$ | +| Gravitation | $\Phi$ [J/kg] | $\boldsymbol{g} = -\nabla \Phi$   [m/s$^2$] | $\nabla\cdot\boldsymbol{g} = -4\pi G\rho_m$ | +| Heat conduction | $T$ [K] | $\boldsymbol{q}_T = -k\nabla T$   [W/m$^2$] | $\nabla\cdot\boldsymbol{q}_T = 0$ (steady, no sources) | +| Groundwater flow | $h$ [m] | $\boldsymbol{q}_h = -K\nabla h$   [m/s] | $\nabla\cdot\boldsymbol{q}_h = 0$ (steady, incompressible) | + +with $k$ the thermal conductivity [W m$^{-1}$ K$^{-1}$] and $K$ the hydraulic conductivity [m/s]. + +The minus signs are all the same minus sign: heat flows from hot to cold, water flows from high head to low, a positive charge falls from high potential to low. Flow runs downhill, and the gradient points uphill. + +The last two rows show why solenoidal fields matter in practice. $\nabla\cdot\boldsymbol{q} = 0$ in an aquifer is not an approximation of convenience; it is conservation of water written locally. + +### Homework + +The exercises in the lecture notes are the written homework. Below is the lab's computational extension, which carries the same two operators into a different physical system. + +**A heat source in a room.** Replace the spherical blob with a flat rectangular heater, $1.0 \times 0.6$ m in the $z = 0$ plane. A steady point source of power $P$ in a medium of conductivity $k$ raises the temperature above ambient by $P/4\pi k r$, the same $1/r$ used throughout this lab. Split the plate into $N = 20 \times 12$ sub-sources, give each an equal share $P/N$ of the power, and superpose them as two charges were superposed in Lab 1's Task 8: + +$$ T(\boldsymbol{r}) = \frac{P}{4\pi k N}\sum_{i=1}^{N} \frac{1}{\lvert \boldsymbol{r} - \boldsymbol{r}_i \rvert}, \qquad P = 100\ \text{W}, \qquad k_{\text{air}} = 0.026\ \text{W m}^{-1}\text{K}^{-1}. $$ + +Check the dimensions before coding: $[P]/[k] = \text{W}/(\text{W m}^{-1}\text{K}^{-1}) = \text{m}\cdot\text{K}$, divided by a distance, so $T$ comes out in kelvin. A temperature formula that does not reduce to kelvin contains an error. Then: + +- Plot the isosurfaces. Close to the plate they should be rounded rectangles; far away they should become spheres. Explain why the shape loses the imprint of its source. +- Compute the heat flux $\boldsymbol{q}_T = -k\nabla T$, with the same minus sign and the same reason as $\boldsymbol{E} = -\nabla V$. +- Check that $\nabla\cdot\boldsymbol{q}_T \approx 0$ away from the heater, and that the closed-surface flux through a box containing the plate is *not* zero. State what each result means physically for a room at steady state, and which of the two fields in Task 2 the heater resembles. +- **Then examine the number.** One metre from a 100 W panel this model predicts about $+290$ K above ambient, a room at 300 °C. The arithmetic is correct, so the physics is wrong. Identify the failed assumption; two are worth naming, namely what actually transports heat through air, and where this solution places the walls of the room. Re-running with $k = 1.5$ W m⁻¹K⁻¹, the conductivity of soil, gives $+5$ K: the same equations now describe a buried heating element, a problem that pure conduction does solve. diff --git a/book/_toc.yml b/book/_toc.yml index 3b9689b..bd29713 100644 --- a/book/_toc.yml +++ b/book/_toc.yml @@ -16,7 +16,8 @@ parts: - file: 1_gradient_divergence_curl/gradient.md - file: 1_gradient_divergence_curl/divergence.md - file: 1_gradient_divergence_curl/curl.md - - file: 1_gradient_divergence_curl/labs/week01-grad-div.md + - file: 1_gradient_divergence_curl/labs/week01_series_grad.md + - file: 1_gradient_divergence_curl/labs/week02_div_curl.md - caption: Potential Fields chapters: - file: 2_potential_fields/introduction/intro.md From bf7fafbf4026ca14f160ccb7336d6d6387f9c6bd Mon Sep 17 00:00:00 2001 From: ARS183 <1028762817@qq.com> Date: Wed, 2 Sep 2026 00:05:29 +0200 Subject: [PATCH 10/17] Stop show_scalar_slice rendering round-off as structure --- book/1_gradient_divergence_curl/labs/fwtools.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/book/1_gradient_divergence_curl/labs/fwtools.py b/book/1_gradient_divergence_curl/labs/fwtools.py index c514f75..6ac4753 100644 --- a/book/1_gradient_divergence_curl/labs/fwtools.py +++ b/book/1_gradient_divergence_curl/labs/fwtools.py @@ -434,6 +434,17 @@ def show_scalar_slice(X, Y, Z, F, *, title="", label="", cmap=None, if vmin is None: vmin = -vmax if symmetric else np.nanpercentile(f2, 100 - percentile) hi, lo = float(vmax), float(vmin) + + # A contour boundary usually falls exactly on 0.0, so a field that is zero + # only to round-off gets sorted into the first warm and the first cool band + # and renders as structure that is not there. The shear flow of Lab 2's + # Task 3 is the case that matters: div = +-5e-15, drawn as faint red lobes, + # which is precisely the "it looks like a source" reading the task exists to + # refute. Anything this far below the plotted range is noise, not signal. + span = max(abs(hi), abs(lo)) + if span > 0.0: + f2 = np.where(np.abs(f2) < 1e-9 * span, 0.0, f2) + lv = np.linspace(lo, hi, levels) created = ax is None From f91fac6e45f2bbae72c4681bc5b95f30f6de0b7c Mon Sep 17 00:00:00 2001 From: ARS183 <1028762817@qq.com> Date: Wed, 2 Sep 2026 00:22:19 +0200 Subject: [PATCH 11/17] Call the irrotational field a straining flow, not a shear --- book/1_gradient_divergence_curl/labs/fwtools.py | 2 +- .../1_gradient_divergence_curl/labs/week02_div_curl.md | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/book/1_gradient_divergence_curl/labs/fwtools.py b/book/1_gradient_divergence_curl/labs/fwtools.py index 6ac4753..df9f8a1 100644 --- a/book/1_gradient_divergence_curl/labs/fwtools.py +++ b/book/1_gradient_divergence_curl/labs/fwtools.py @@ -437,7 +437,7 @@ def show_scalar_slice(X, Y, Z, F, *, title="", label="", cmap=None, # A contour boundary usually falls exactly on 0.0, so a field that is zero # only to round-off gets sorted into the first warm and the first cool band - # and renders as structure that is not there. The shear flow of Lab 2's + # and renders as structure that is not there. The straining flow of Lab 2's # Task 3 is the case that matters: div = +-5e-15, drawn as faint red lobes, # which is precisely the "it looks like a source" reading the task exists to # refute. Anything this far below the plotted range is noise, not signal. diff --git a/book/1_gradient_divergence_curl/labs/week02_div_curl.md b/book/1_gradient_divergence_curl/labs/week02_div_curl.md index 1e28d5f..d644589 100644 --- a/book/1_gradient_divergence_curl/labs/week02_div_curl.md +++ b/book/1_gradient_divergence_curl/labs/week02_div_curl.md @@ -348,13 +348,13 @@ div_c = ___ # --- given: the three side by side, one shared scale, one colorbar --- for name, d in [("(a) outward flow", div_a), ("(b) rotation", div_b), - ("(c) shear", div_c)]: + ("(c) straining flow", div_c)]: print(f"{name:20s} div = {d.mean():+.3f}") fig, axes = plt.subplots(1, 3, figsize=(16, 4.6)) for ax_, (name, A, d) in zip(axes, [("(a) outward flow", Aa, div_a), ("(b) rotation", Ab, div_b), - ("(c) shear flow", Ac, div_c)]): + ("(c) straining flow", Ac, div_c)]): fw.show_field_slice(X, Y, Z, *A[:2], background=d, ax=ax_, density=1.1, vmin=-3, vmax=3, colorbar=(ax_ is axes[-1]), label=r"$\nabla\cdot\mathbf{A}$ [s$^{-1}$]", title=name) @@ -369,7 +369,7 @@ plt.show() # tolerance instead. fw.check_close("(a) div = 3", div_a, 3.0, rtol=1e-6) fw.check_abs("(b) div = 0 (rotation)", div_b, atol=1e-9) -fw.check_abs("(c) div = 0 (shear)", div_c, atol=1e-9) +fw.check_abs("(c) div = 0 (straining flow)", div_c, atol=1e-9) for key, measured in (("a", div_a), ("b", div_b), ("c", div_c)): sign = int(np.sign(np.round(measured.mean(), 6))) @@ -610,8 +610,8 @@ for h in (0.6, 1.0, 1.4): # Task 3 settled by measurement rather than by argument. Both (b) and (c) # appear to throw fluid outwards somewhere; a closed surface is the arbiter, # and it differentiates nothing. -print(f"\nflux of (b), the rotation : {closed_box_flux(-Y, X, zero, 1.0):+.2e}") -print(f"flux of (c), the shear : {closed_box_flux(X, -Y, zero, 1.0):+.2e}") +print(f"\nflux of (b), the rotation : {closed_box_flux(-Y, X, zero, 1.0):+.2e}") +print(f"flux of (c), the straining flow : {closed_box_flux(X, -Y, zero, 1.0):+.2e}") # --- self-check (leave this alone) --- i0, i1 = fw.box_indices(X, 1.0) From cd5082260b4bdd45e53dbf1dcf2f55a762e3eb39 Mon Sep 17 00:00:00 2001 From: ARS183 <1028762817@qq.com> Date: Wed, 2 Sep 2026 18:37:51 +0200 Subject: [PATCH 12/17] Add line_integral, a stream colour and a general round-off guard to fwtools --- .../labs/fwtools.py | 53 +++++++++++++------ 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/book/1_gradient_divergence_curl/labs/fwtools.py b/book/1_gradient_divergence_curl/labs/fwtools.py index df9f8a1..3c0bcd0 100644 --- a/book/1_gradient_divergence_curl/labs/fwtools.py +++ b/book/1_gradient_divergence_curl/labs/fwtools.py @@ -20,7 +20,7 @@ __all__ = [ "z0_index", "slice_z0", - "box_indices", "area_integral", "volume_integral", + "box_indices", "line_integral", "area_integral", "volume_integral", "show_isosurfaces", "show_cones", "show_scalar_slice", "show_field_slice", "check", "check_shape", "check_close", "check_abs", "check_scalar", ] @@ -40,11 +40,12 @@ def slice_z0(F: np.ndarray, Z: np.ndarray) -> np.ndarray: # -------------------------------------------------------------------------- -# Integration over grid-aligned boxes and faces +# Integration over grid-aligned boxes, faces and edges # -# These evaluate the integrals in the definition of the divergence and in the -# divergence theorem. They are quadrature boilerplate: the trapezoidal weights -# below simply stop the end samples from being counted as full cells. +# These evaluate the integrals in the definitions of the divergence and the +# curl, and in the divergence and Stokes theorems. They are quadrature +# boilerplate: the trapezoidal weights below simply stop the end samples +# from being counted as full cells. # -------------------------------------------------------------------------- def _trapezoid_weights(n: int) -> np.ndarray: @@ -67,6 +68,18 @@ def box_indices(X: np.ndarray, half_width: float): return i0, i1 +def line_integral(F1: np.ndarray, ds: float) -> float: + """Integrate a 1-D array of samples along the line it spans. + + One edge of a closed loop, for the circulation integral, the way + ``area_integral`` handles one face of a box for the flux. Same + trapezoidal rule, same refusal to integrate over masked samples. + """ + F1 = np.asarray(F1, float) + _reject_masked(F1, "This edge passes through masked samples") + return float(np.sum(F1 * _trapezoid_weights(F1.shape[0])) * ds) + + def area_integral(F2: np.ndarray, da: float, db: float) -> float: """Integrate a 2-D array of samples over the rectangle it spans. @@ -435,15 +448,20 @@ def show_scalar_slice(X, Y, Z, F, *, title="", label="", cmap=None, vmin = -vmax if symmetric else np.nanpercentile(f2, 100 - percentile) hi, lo = float(vmax), float(vmin) - # A contour boundary usually falls exactly on 0.0, so a field that is zero - # only to round-off gets sorted into the first warm and the first cool band - # and renders as structure that is not there. The straining flow of Lab 2's - # Task 3 is the case that matters: div = +-5e-15, drawn as faint red lobes, - # which is precisely the "it looks like a source" reading the task exists to - # refute. Anything this far below the plotted range is noise, not signal. + # Contour boundaries land on round numbers, and the exact answers in this + # course are round numbers, so a field that is constant to round-off gets + # its cells sorted into the bands either side of a boundary and renders as + # structure that is not there. Both cases in Lab 2 are of that kind: the + # straining flow of Task 3 is div = +-5e-15 against a boundary at 0.0, + # drawn as faint red lobes, which is precisely the "it looks like a source" + # reading the task exists to refute; the rotation of Task 6 is curl = 2 + # +- 1e-15 against a boundary at 2.0, drawn as a patchwork. Quantising at + # a billionth of the plotted range is far below any band and far above + # double-precision noise, so it removes the artefact and nothing else. span = max(abs(hi), abs(lo)) if span > 0.0: - f2 = np.where(np.abs(f2) < 1e-9 * span, 0.0, f2) + q = 1e-9 * span + f2 = np.round(f2 / q) * q lv = np.linspace(lo, hi, levels) @@ -463,7 +481,7 @@ def show_scalar_slice(X, Y, Z, F, *, title="", label="", cmap=None, def show_field_slice(X, Y, Z, Ax, Ay, *, background=None, title="", label="", cmap="RdBu_r", density=1.3, symmetric=True, ax=None, percentile=98, colorbar=True, vmin=None, vmax=None, - plane="z"): + plane="z", levels=25, stream_color="k"): """Streamlines of a vector field on a coordinate plane, over an optional scalar background (typically the potential that generated it). @@ -474,6 +492,11 @@ def show_field_slice(X, Y, Z, Ax, Ay, *, background=None, title="", label="", if no background was given; pass ``colorbar=False`` on every panel of a multi-panel figure and hand ``cf`` to ``fig.colorbar(cf, ax=axes, ...)`` to draw a single bar spanning the lot. + + ``stream_color`` is the colour of the streamlines. Black reads well on a + diverging map, which is pale in the middle, and disappears on a sequential + one, which is dark at the bottom; pass ``"w"`` over ``inferno`` or + ``viridis``. """ created = ax is None if created: @@ -483,7 +506,7 @@ def show_field_slice(X, Y, Z, Ax, Ay, *, background=None, title="", label="", if background is not None: _, cf = show_scalar_slice(X, Y, Z, background, cmap=cmap, symmetric=symmetric, percentile=percentile, ax=ax, colorbar=False, - vmin=vmin, vmax=vmax, plane=plane) + vmin=vmin, vmax=vmax, plane=plane, levels=levels) # streamplot needs 1-D increasing axes and arrays shaped (nb, na); our # indexing='ij' arrays are (na, nb), hence the transposes. @@ -491,7 +514,7 @@ def show_field_slice(X, Y, Z, Ax, Ay, *, background=None, title="", label="", _, _, v2, _, _ = _plane_slice(X, Y, Z, Ay, plane) u = np.nan_to_num(u2).T v = np.nan_to_num(v2).T - ax.streamplot(x1, y1, u, v, color="k", linewidth=0.7, + ax.streamplot(x1, y1, u, v, color=stream_color, linewidth=0.7, density=density, arrowsize=0.9) ax.set_aspect("equal") From 4f45587083712ba663e4627509f72ccf0e21b79b Mon Sep 17 00:00:00 2001 From: ARS183 <1028762817@qq.com> Date: Wed, 2 Sep 2026 18:37:51 +0200 Subject: [PATCH 13/17] Ask for two of the three lines of divergence, as Task 6 will for curl --- .../labs/week02_div_curl.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/book/1_gradient_divergence_curl/labs/week02_div_curl.md b/book/1_gradient_divergence_curl/labs/week02_div_curl.md index d644589..230afcd 100644 --- a/book/1_gradient_divergence_curl/labs/week02_div_curl.md +++ b/book/1_gradient_divergence_curl/labs/week02_div_curl.md @@ -143,18 +143,18 @@ Read the definition on the left rather than the formula on the right: **treat $\ ### Task 1 — the operator, and its independence of the origin -The operator is three lines, and they are given. One derivative along one axis per component: `np.gradient(Ax, dx, axis=0)` returns $\partial A_x/\partial x$ and nothing else, whereas asking for all three and discarding two costs three times the memory. The cross terms are not part of a divergence. +The operator is three lines. One derivative along one axis per component: `np.gradient(Ax, dx, axis=0)` returns $\partial A_x/\partial x$ and nothing else, whereas asking for all three and discarding two costs three times the memory. The cross terms are not part of a divergence. **The question is the one raised by the definition.** Flux per unit volume is measured around a point, so does the result depend on which point is called the origin? Take the outward flow $\boldsymbol{A} = \boldsymbol{r}$, whose divergence follows on paper as $1+1+1 = 3$, then shift the whole field so that it streams out of $(0.8, -0.4, 0.3)$. Predict the divergence before computing it. ```{code-cell} ipython3 -# --- given --- +# Task 1 def divergence(Ax, Ay, Az, dx, dy, dz): return (np.gradient(Ax, dx, axis=0) - + np.gradient(Ay, dy, axis=1) - + np.gradient(Az, dz, axis=2)) + + ___ + + ___) -# Task 1 -- two blanks. The same outward flow, seen from somewhere else. +# The same outward flow, seen from somewhere else. x0, y0, z0 = 0.8, -0.4, 0.3 Sx, Sy, Sz = ___ # the field r - r0, as three arrays div_shifted = ___ # its divergence @@ -172,6 +172,11 @@ fw.check("the shifted field really is different from the original", :class: dropdown ```python +def divergence(Ax, Ay, Az, dx, dy, dz): + return (np.gradient(Ax, dx, axis=0) + + np.gradient(Ay, dy, axis=1) + + np.gradient(Az, dz, axis=2)) + Sx, Sy, Sz = X - x0, Y - y0, Z - z0 div_shifted = divergence(Sx, Sy, Sz, dx, dy, dz) ``` From 4a47f9230e27f99341bb3b215e65960afede7bbf Mon Sep 17 00:00:00 2001 From: ARS183 <1028762817@qq.com> Date: Wed, 2 Sep 2026 18:37:51 +0200 Subject: [PATCH 14/17] Say why Task 2 divides by |v|/r, and print the raw divergence beside it --- .../labs/week02_div_curl.md | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/book/1_gradient_divergence_curl/labs/week02_div_curl.md b/book/1_gradient_divergence_curl/labs/week02_div_curl.md index 230afcd..1617b51 100644 --- a/book/1_gradient_divergence_curl/labs/week02_div_curl.md +++ b/book/1_gradient_divergence_curl/labs/week02_div_curl.md @@ -202,19 +202,27 @@ $$ \nabla\cdot\boldsymbol{v} = 3f(r) + r\frac{df}{dr} = 0 \qquad\Longrightarrow\ Rather than assume this, test four candidates and let the divergence select. +One decision comes first, because the four candidates are not the same size. Over the test band their divergences span a factor of a thousand, and the raw numbers cannot be ranked against each other: $f = 1/r^{4}$ returns a *smaller* $\lvert\nabla\cdot\boldsymbol{v}\rvert$ than $f = \text{const}$ does, and neither field is divergence-free. "Is 0.36 small?" has no answer until it is small compared with something. + +The something is the size a derivative of that same field would have if nothing cancelled. A derivative is a change in $\boldsymbol{v}$ divided by the distance over which it changes, and for a radial field $f(r)\boldsymbol{r}$ the only distance available is $r$ itself. That makes $\lvert\boldsymbol{v}\rvert/r$ the yardstick, and + +$$ \frac{\lvert\nabla\cdot\boldsymbol{v}\rvert}{\lvert\boldsymbol{v}\rvert/r} $$ + +a pure number, the same for a trickle and a torrent: **1 means the three terms of the divergence did not cancel at all, and 0 means they cancelled completely.** The cell prints the raw divergence beside the ratio, so you can see for yourself why the raw column is unusable. + +One entry is known before the code runs. For $f = \text{const}$ the field is $\boldsymbol{v} = \boldsymbol{r}$, so $\lvert\boldsymbol{v}\rvert/r = 1$ and the ratio is nothing but $\nabla\cdot\boldsymbol{r} = 3$, which Task 1 measured. That row is the check that the statistic is being formed correctly, and it is why the last self-check looks for 300%. + ```{code-cell} ipython3 -# The measure reported by the loop below: -# -# |div v| / (|v| / r), median over the test band -# -# |v|/r is the natural size of a derivative of v, so the ratio is a pure -# number: 1 means "as large as a derivative of this field could be". +# The statistic, restated: |div v| / (|v|/r), median over the test band. +# The band avoids the source, where the field is singular, and the outer +# corners of the box, where np.gradient runs out of neighbours. r_safe = np.where(r < 0.3, np.nan, r) band_i = interior & (r > 0.6) & (r < 1.6) # Task 2 -- three blanks, inside the loop. -results = {} +results, raws = {}, {} +print(f" {'f(r)':>7} {'|div v|':>11} {'|v|/r':>8} {'ratio':>9}") for name, f_r in [("const", np.ones_like(r_safe)), ("1/r^2", 1/r_safe**2), ("1/r^3", 1/r_safe**3), @@ -226,10 +234,15 @@ for name, f_r in [("const", np.ones_like(r_safe)), # and the same length as dv[band_i] # --- given --- + raws[name] = np.nanmedian(np.abs(dv[band_i])) results[name] = np.nanmedian(np.abs(dv[band_i]) / scale) - print(f" f = {name:6s}: median |div v| / (|v|/r) = {results[name]:8.2%}") + print(f" {name:>7} {raws[name]:11.4f} {np.nanmedian(scale):8.4f}" + f" {results[name]:9.2%}") # --- self-check (leave this alone) --- +fw.check(f"the raw column cannot rank these: 1/r^4 gives a smaller |div v| " + f"({raws['1/r^4']:.3f}) than f = const ({raws['const']:.3f}), and " + f"neither is divergence-free", raws["1/r^4"] < raws["const"]) fw.check(f"scale is one value per band point ({np.shape(scale)} vs " f"{np.shape(dv[band_i])})", np.shape(scale) == np.shape(dv[band_i]), "index it with [band_i] -- a whole-grid array or a single median " @@ -255,9 +268,7 @@ fw.check(f"f = const reproduces Task 1's div(r) = 3 ({results['const']:.2%})", :::{admonition} Where the inverse-square law comes from :class: important -One candidate gives 300%, two give almost exactly 100%, and one gives 0.66%. Only $f = A/r^{3}$ survives, as the algebra predicts. - -The 300% is not an accident. For $f = \text{const}$ the field is the position vector, $\boldsymbol{v} = \boldsymbol{r}$, whose divergence Task 1 measured as exactly 3, while $\lvert\boldsymbol{v}\rvert/r = 1$, so the ratio must be 3. The surviving case rewrites as +Two candidates give almost exactly 100%, meaning their three divergence terms did not cancel at all, and the anchor gives its predicted 300%. One gives 0.66%. Only $f = A/r^{3}$ survives, as the algebra predicts, and the raw column beside it would have told you none of this. The surviving case rewrites as $$ \boldsymbol{v} = \frac{A}{r^{3}}\boldsymbol{r} = \frac{A}{r^{2}}\,\hat{\boldsymbol{r}}. $$ From ffeff822a390589711d4648b097d3a46038cbd14 Mon Sep 17 00:00:00 2001 From: ARS183 <1028762817@qq.com> Date: Wed, 2 Sep 2026 18:37:51 +0200 Subject: [PATCH 15/17] Add Part 3, the curl, and rework the closing for three operators --- .../labs/week02_div_curl.md | 485 +++++++++++++++++- 1 file changed, 470 insertions(+), 15 deletions(-) diff --git a/book/1_gradient_divergence_curl/labs/week02_div_curl.md b/book/1_gradient_divergence_curl/labs/week02_div_curl.md index 1617b51..a4deeb5 100644 --- a/book/1_gradient_divergence_curl/labs/week02_div_curl.md +++ b/book/1_gradient_divergence_curl/labs/week02_div_curl.md @@ -19,7 +19,7 @@ mystnb: :::{admonition} Computer lab :class: note -The second of two labs on the operators of this chapter, following Lab 1 on series and the gradient. Each task states a physical question, gives the steps, and ends with a self-check you can run. Plotting is supplied in the module `fwtools`, so that your effort goes into the physics rather than into rendering transparent isosurfaces. +The second of two labs on the operators of this chapter, following Lab 1 on series and the gradient. Parts 1 and 2 take the divergence, Part 3 the curl. Each task states a physical question, gives the steps, and ends with a self-check you can run. Plotting is supplied in the module `fwtools`, so that your effort goes into the physics rather than into rendering transparent isosurfaces. ::: ## Learning objectives @@ -28,6 +28,7 @@ By the end of this lab you should be able to: - **Distinguish diverging arrows from non-zero divergence.** Compute $\nabla\cdot\boldsymbol{v}$, justify the result by flux rather than by algebra, and identify the only radial flow that is incompressible. - **Use the divergence theorem as a measurement.** Verify $\oint_S\boldsymbol{v}\cdot\hat{\boldsymbol{n}}\,dS = \int_{\mathcal{D}} \nabla\cdot\boldsymbol{v}\,dV$ numerically, and account for what happens when the source shrinks to a point. +- **Measure the curl as circulation per unit area.** Compute $\nabla\times\boldsymbol{v}$, separate rotation from the shape a streamline happens to make, and verify Stokes' theorem on a vortex with a finite core. --- @@ -787,31 +788,481 @@ The 1.06% in Task 4 is therefore not noise to be tolerated but a predictable qua ## Part 3 — Curl -Return to field **(b)**, the rotation. Its divergence is zero everywhere, so by that measure it is indistinguishable from a field doing nothing. It nevertheless circulates, and every streamline closes on itself. +Field **(b)**, the rotation, has zero divergence everywhere, yet it plainly circulates. The divergence cannot detect circulation. The operator that can is the **curl**, which takes a vector field and returns another vector field: -The divergence cannot detect circulation. The operator that can is the **curl**, the third of the three operators this chapter is named after. +$$ \nabla\times\boldsymbol{v} \;=\; \hat{\boldsymbol{x}}\left(\partial_y v_z - \partial_z v_y\right) + \hat{\boldsymbol{y}}\left(\partial_z v_x - \partial_x v_z\right) + \hat{\boldsymbol{z}}\left(\partial_x v_y - \partial_y v_x\right) $$ -:::{admonition} Exercises to follow -:class: note +There is no determinant to memorise. Each component pairs an even permutation of $(x,y,z)$ against an odd one, in three places at once: the direction, the differentiation, and the vector component. The $\hat{\boldsymbol{x}}$ term takes $(x,y,z)$ minus $(x,z,y)$, and the other two follow by advancing every letter one step, $x\to y\to z\to x$. + +The interpretation comes from a circulation integral. Take a small rectangle of side $dy$ by $dz$ around a point, walk its four edges once round, and add up the component of $\boldsymbol{v}$ along the direction of travel. Expanding each edge to first order in a Taylor series leaves + +$$ \oint_{\boldsymbol{r}}\boldsymbol{\tau}\cdot\boldsymbol{v}\;dl \;=\; \left(\partial_y v_z - \partial_z v_y\right)dy\,dz \;+\; \text{higher order} $$ + +with $\boldsymbol{\tau}$ the unit tangent along the path. That is the $\hat{\boldsymbol{x}}$ component of the curl times the area of the rectangle, and rectangles perpendicular to $\hat{\boldsymbol{y}}$ and $\hat{\boldsymbol{z}}$ give the other two. So the curl is **net circulation per unit area**: + +$$ \hat{\boldsymbol{n}}\cdot\left(\nabla\times\boldsymbol{v}\right) \;=\; \lim_{S\to 0}\frac{\oint_{\boldsymbol{r}}\boldsymbol{\tau}\cdot\boldsymbol{v}\;dl}{A} $$ + +where $A$ is the area of the open surface $S$ and $\hat{\boldsymbol{n}}$ is its unit normal, oriented so that a right-handed screw turned in the direction of $\boldsymbol{\tau}$ advances along $\hat{\boldsymbol{n}}$. Part 1 built the divergence from flux through a closed surface. The curl is built from circulation around a closed curve, one dimension down. + +### Task 6 — the operator, and the three flows again + +Three lines, in the pattern of the formula above. `np.gradient(Az, dy, axis=1)` is $\partial_y v_z$: the array holding the $z$-component, differentiated along the $y$-axis. + +Put the three fields of Task 3 through it. Field (b) rotates rigidly about the $z$-axis at $\omega = 1$ s$^{-1}$, so a paddle wheel dropped anywhere in it turns; fields (a) and (c) carry no rotation. Predict all three before running the cell. + +```{code-cell} ipython3 +# Task 6 -- two blanks. The x-component is given. Advance every letter one +# step, x -> y -> z -> x, in the direction, the differentiation and the +# component, and the other two lines write themselves. +def curl(Ax, Ay, Az, dx, dy, dz): + cx = np.gradient(Az, dy, axis=1) - np.gradient(Ay, dz, axis=2) + cy = ___ + cz = ___ + return cx, cy, cz + +# --- given: the three fields of Task 3, through the new operator, and one +# more. Field (d) is the same rigid rotation turned onto the y-axis, so +# its curl is 2 y-hat: it is here to exercise the second line you wrote, +# which the three planar fields above leave at zero whatever you put in it. +Ad = (Z, zero, -X) +curl_a, curl_b = curl(*Aa, dx, dy, dz), curl(*Ab, dx, dy, dz) +curl_c, curl_d = curl(*Ac, dx, dy, dz), curl(*Ad, dx, dy, dz) + +for name, w in [("(a) outward flow", curl_a), ("(b) rotation about z", curl_b), + ("(c) straining flow", curl_c), ("(d) rotation about y", curl_d)]: + print(f"{name:22s} curl = ({w[0].mean():+.2f}, {w[1].mean():+.2f}, {w[2].mean():+.2f})") + +fig, axes = plt.subplots(1, 3, figsize=(16, 4.6)) +for ax_, (name, A, w) in zip(axes, [("(a) outward flow", Aa, curl_a), + ("(b) rotation", Ab, curl_b), + ("(c) straining flow", Ac, curl_c)]): + fw.show_field_slice(X, Y, Z, *A[:2], background=w[2], ax=ax_, density=1.1, + vmin=-3, vmax=3, colorbar=(ax_ is axes[-1]), + label=r"$(\nabla\times\mathbf{A})_z$ [s$^{-1}$]", title=name) +plt.tight_layout() +plt.show() + +# --- self-check (leave this alone) --- +# Each test reads the whole vector, not one component: a sign slip in `cy` +# leaves every planar field untouched and would otherwise pass unnoticed. +def _mag(w): + return np.sqrt(w[0]**2 + w[1]**2 + w[2]**2) + +fw.check_abs("(a) curl = 0 (outward flow)", _mag(curl_a), atol=1e-9) +fw.check_abs("(c) curl = 0 (straining flow)", _mag(curl_c), atol=1e-9) +fw.check_close("(b) curl = 2 z-hat", curl_b[2], 2.0, rtol=1e-6) +fw.check_abs("...and nothing along x or y", + np.abs(curl_b[0]) + np.abs(curl_b[1]), atol=1e-9) +fw.check_close("(d) curl = 2 y-hat", curl_d[1], 2.0, rtol=1e-6, + where=interior) +fw.check_abs("...and nothing along x or z", + (np.abs(curl_d[0]) + np.abs(curl_d[2]))[interior], atol=1e-9) +``` -The computer exercises for the curl are not drafted yet. They will build on the circulation -integral and Stokes' theorem, using field **(b)** of Task 3 as the first test case. +:::{admonition} Solution — Task 6 +:class: dropdown + +```python + cy = np.gradient(Ax, dz, axis=2) - np.gradient(Az, dx, axis=0) + cz = np.gradient(Ay, dx, axis=0) - np.gradient(Ax, dy, axis=1) +``` +::: + +:::{admonition} Two independent questions about one field +:class: important + +The three flows of Task 3 now carry two answers each, and neither constrains the other: + +| | Field $\boldsymbol{A}$ | $\nabla\cdot\boldsymbol{A}$ | $\nabla\times\boldsymbol{A}$ | +| :---: | :--- | :---: | :---: | +| **(a)** | $x\,\hat{\boldsymbol{x}} + y\,\hat{\boldsymbol{y}} + z\,\hat{\boldsymbol{z}}$ | $3$ | $\boldsymbol{0}$ | +| **(b)** | $-y\,\hat{\boldsymbol{x}} + x\,\hat{\boldsymbol{y}}$ | $0$ | $2\,\hat{\boldsymbol{z}}$ | +| **(c)** | $x\,\hat{\boldsymbol{x}} - y\,\hat{\boldsymbol{y}}$ | $0$ | $\boldsymbol{0}$ | + +"How much is created here" and "how much does this spin here" are separate measurements. Field (c) answers zero to both and is still not the zero field: it stretches a fluid parcel along $x$ and squeezes it along $y$ at equal rates, changing its shape while conserving its volume and its orientation. Deformation is the third thing a flow can do, and neither operator reports it. + +Field (b) rotates at $\omega = 1$ s$^{-1}$ and its curl is $2\hat{\boldsymbol{z}}$. For rigid rotation at angular velocity $\boldsymbol{\omega}$ the curl is $2\boldsymbol{\omega}$, whatever the axis, which is why field (d) about $\hat{\boldsymbol{y}}$ returns $2\hat{\boldsymbol{y}}$. In fluid mechanics $\nabla\times\boldsymbol{v}$ is the **vorticity**, twice the local angular velocity of a fluid parcel. +::: + +### Task 7 — closed streamlines are not curl + +Task 3 established that arrows spreading apart do not make a divergence. The same warning applies here, in the same shape, and the two errors are the same error. **The picture a streamline makes says nothing about the curl.** + +Two fields settle it, with the rotation of Task 6 as a control. Both are written on the distance from the $z$-axis, the cylindrical $\varrho = \sqrt{x^2+y^2}$, which is not the spherical $r$ of Parts 1 and 2. + +| | Field | Streamlines | +| :---: | :--- | :--- | +| **rotation** | $\omega\,\varrho\,\hat{\boldsymbol{\phi}} \;=\; -y\,\hat{\boldsymbol{x}} + x\,\hat{\boldsymbol{y}}$ | concentric circles | +| **shear** | $\sigma\,y\,\hat{\boldsymbol{x}}$ | straight lines, all parallel to $x$ | +| **line vortex** | $\dfrac{\Gamma_0}{2\pi\varrho}\hat{\boldsymbol{\phi}} \;=\; \Gamma_0\dfrac{-y\,\hat{\boldsymbol{x}} + x\,\hat{\boldsymbol{y}}}{2\pi\varrho^{2}}$ | concentric circles | + +with $\omega = 1$ s$^{-1}$, shear rate $\sigma = 1$ s$^{-1}$ and $\Gamma_0 = 2\pi$ m$^2$/s, so all three curls come out in s$^{-1}$ and one colour scale serves the row. + +The shear is the water beside a riverbank, or between two plates sliding past each other: further out it runs faster, but every parcel travels in a straight line and none of them goes round anything. The line vortex circles the axis exactly as the rotation does, and falls off as $1/\varrho$. Record your prediction of the sign of $(\nabla\times\boldsymbol{v})_z$ for each, then measure. + +```{code-cell} ipython3 +# +1 for anticlockwise rotation, -1 for clockwise, 0 for none. +curl_predictions = {"rotation": ___, "shear": ___, "line vortex": ___} +``` + +```{code-cell} ipython3 +# --- given: distance from the z-axis, and a test region that avoids it --- +varrho = np.sqrt(X**2 + Y**2) +varrho_s = np.maximum(varrho, 1e-12) # the axis kept out of the denominators +ring = interior & (varrho > 0.4) & (varrho < 1.6) + +# Task 7 -- two blanks, one field each. Both lie in the z = 0 plane, so the +# third component of each is `zero`. Take Gamma_0 / 2*pi = 1, as above. +A_shear = ___ # y x-hat, as a triple +A_vortex = ___ # (-Y, X) / varrho_s**2, as a triple + +# --- given --- +curl_shear = curl(*A_shear, dx, dy, dz) +curl_vortex = curl(*A_vortex, dx, dy, dz) + +# Reported as the scale-free ratio Task 2 built for the divergence, with the +# distance from the AXIS in place of the distance from the origin: the size of +# the curl against |v|/varrho, the size a derivative of this field would have +# if nothing cancelled. Same reasoning, same reading: 1 means no cancellation. +v_mag = np.sqrt(A_vortex[0]**2 + A_vortex[1]**2) +vortex_ratio = np.median(np.abs(curl_vortex[2][ring]) / (v_mag / varrho_s)[ring]) +measured = {"rotation": curl_b[2].mean(), "shear": curl_shear[2][ring].mean(), + "line vortex": curl_vortex[2][ring].mean()} +print(f"rotation : curl_z = {measured['rotation']:+.3f} s^-1") +print(f"shear : curl_z = {measured['shear']:+.3f} s^-1") +print(f"line vortex : |curl_z| / (|v|/varrho) = {vortex_ratio:.2%} (zero, to grid error)") +# The vortex is zero only to grid error, so the score needs a deadband: +# anything under 5% of the largest curl in the row counts as no rotation. +deadband = 0.05 * max(abs(v) for v in measured.values()) +for key, got in measured.items(): + sign = 0 if abs(got) < deadband else int(np.sign(got)) + verdict = "as predicted" if curl_predictions[key] == sign else "NOT what you predicted" + print(f" {key:12s} you said {curl_predictions[key]:+d}, measured {sign:+d} -- {verdict}") + +# The vortex is singular on the z-axis. What the operator returns on the few +# cells around it is the grid's difficulty and not the field's, so those cells +# are left blank rather than allowed to dominate the panel. +shown = np.where(varrho < 0.3, np.nan, curl_vortex[2]) + +fig, axes = plt.subplots(1, 3, figsize=(16, 4.6)) +panels = [("rotation", Ab, curl_b[2]), ("shear", A_shear, curl_shear[2]), + ("line vortex", A_vortex, shown)] +for ax_, (name, A, w) in zip(axes, panels): + fw.show_field_slice(X, Y, Z, *A[:2], background=w, ax=ax_, density=1.1, + vmin=-3, vmax=3, colorbar=(ax_ is axes[-1]), + label=r"$(\nabla\times\mathbf{v})_z$ [s$^{-1}$]", title=name) +plt.tight_layout() +plt.show() + +# --- self-check (leave this alone) --- +fw.check_close("shear: curl = -1 z-hat, although nothing goes round", + curl_shear[2][ring], -1.0, rtol=1e-6) +fw.check(f"line vortex: curl = 0, although everything goes round ({vortex_ratio:.2%})", + vortex_ratio < 0.05) +fw.check("...and it really does circle the axis: v has no radial component", + np.max(np.abs((A_vortex[0]*X + A_vortex[1]*Y)[ring])) < 1e-12) +``` + +:::{admonition} Solution — Task 7 +:class: dropdown + +```python +A_shear = (Y, zero, zero) +A_vortex = (-Y / varrho_s**2, X / varrho_s**2, zero) +``` +::: + +:::{admonition} What the paddle wheel actually measures +:class: warning + +Drop a small paddle wheel into each flow and watch its axle. + +In the **shear** it spins, at half a radian per second, clockwise. The water above the wheel runs faster than the water below, so the top blades are pushed harder than the bottom ones. Nothing in the flow travels in a circle and the curl is still $-\hat{\boldsymbol{z}}$. + +In the **line vortex** the wheel is carried once round the axis and comes back pointing the way it started. It orbits without spinning, like the Moon in reverse. Two separate effects cancel, and the cylindrical formula separates them. For a field $v_\phi(\varrho)\,\hat{\boldsymbol{\phi}}$, + +$$ (\nabla\times\boldsymbol{v})_z = \frac{1}{\varrho}\frac{\partial\left(\varrho\, v_\phi\right)}{\partial\varrho} - \frac{1}{\varrho}\frac{\partial v_\varrho}{\partial \phi} \;=\; \underbrace{\frac{dv_\phi}{d\varrho}}_{\text{shear}} + \underbrace{\frac{v_\phi}{\varrho}}_{\text{orbit}} $$ + +the second term dropping because these fields have no radial component. The **shear** term is the blades: the inner ones sit in faster water than the outer ones, which turns the wheel backwards, at $-\Gamma_0/2\pi\varrho^{2}$. The **orbit** term is the wheel's own frame turning once per lap, forwards, at $+\Gamma_0/2\pi\varrho^{2}$. Their sum is zero at $1/\varrho$ and at no other falloff: a steeper $1/\varrho^{2}$ over-cancels and spins the wheel backwards, a shallower one spins it forwards. Their *mean* is the local angular velocity, which is where Task 6's factor of two comes from. + +Read the same formula the other way and the curl vanishes when $\varrho\,v_\phi$ is constant, which is $v_\phi \propto 1/\varrho$ and nothing else. Rigid rotation, $v_\phi = \omega\varrho$, gives $2\omega$ instead. + +That single surviving field, $\boldsymbol{H} = \dfrac{I}{2\pi\varrho}\hat{\boldsymbol{\phi}}$, is the magnetic field around a straight wire carrying a current $I$. Its curl is zero at every point outside the wire, and the current is still there. The end of this part explains how both can be true. +::: + +### Task 8 — circulation per unit area, and Stokes' theorem + +A real vortex has a core. Stirred coffee, a tornado and the vortex trailing from a wing all rotate almost rigidly near the axis and fall off as $1/\varrho$ far from it, because viscosity spreads the vorticity over a finite radius $b$. The **Lamb–Oseen vortex** is the exact solution for that spreading, with $b^{2} = 4\nu t$ after a time $t$ in a fluid of kinematic viscosity $\nu$: + +$$ v_\phi(\varrho) = \frac{\Gamma}{2\pi\varrho}\left(1 - e^{-\varrho^{2}/b^{2}}\right), \qquad \Gamma = 1\ \text{m}^2\text{/s}, \qquad b = 0.5\ \text{m}. $$ + +Inside the core this is $\Gamma\varrho/2\pi b^{2}$, the rigid rotation of Task 6. Outside it is $\Gamma/2\pi\varrho$, the irrotational vortex of Task 7. The cylindrical formula turns it into a vorticity that is a Gaussian blob: + +$$ (\nabla\times\boldsymbol{v})_z = \frac{1}{\varrho}\frac{d}{d\varrho}\left(\varrho\,v_\phi\right) = \frac{\Gamma}{\pi b^{2}}\,e^{-\varrho^{2}/b^{2}} $$ + +the same shape as Task 4's blob of charge, with $\Gamma$ in the part of $Q$. The rest of this task is Part 2 run one dimension down: a closed curve instead of a closed surface, circulation instead of flux, and **Stokes' theorem** instead of the divergence theorem, + +$$ \oint_{\boldsymbol{r}}\boldsymbol{\tau}\cdot\boldsymbol{v}\;dl \;=\; \int_{\boldsymbol{r}\in S}\hat{\boldsymbol{n}}\cdot\left(\nabla\times\boldsymbol{v}\right)dS $$ + +```{code-cell} ipython3 +Gamma, b_core = 1.0, 0.5 # circulation [m^2/s], core radius b [m] + +# --- given: the vortex, and the vorticity it should have --- +_swirl = np.where(varrho < 1e-8, Gamma / (2*np.pi*b_core**2), + Gamma / (2*np.pi*varrho_s**2) * (1 - np.exp(-varrho**2/b_core**2))) +oseen = (-Y * _swirl, X * _swirl, zero) # v_phi phi-hat, in Cartesian components +w_exact = Gamma / (np.pi * b_core**2) * np.exp(-varrho**2 / b_core**2) +curl_oseen = curl(*oseen, dx, dy, dz) + +# Task 8 -- two blanks, one per side of Stokes' theorem. +# +# LEFT SIDE. Walk the four edges of a rectangle in the z = 0 plane once +# counter-clockwise, so the right-hand rule puts the unit normal along +z-hat, +# and add up the component of the field along the direction of travel: +# +# edge samples along it travelling spacing sign +# y = y0 Ax[sx, iy0, k] +x dx + +# x = x1 Ay[ix1, sy, k] +y dy + +# y = y1 Ax[sx, iy1, k] -x dx - +# x = x0 Ay[ix0, sy, k] -y dy - +# +# The two edges walked backwards enter negatively, exactly as the inward faces +# did in Task 5. The x pair is written for you. + +def loop_circulation(Ax, Ay, x0, x1, y0, y1): + """Counter-clockwise circulation of (Ax, Ay) round a rectangle in z = 0.""" + ix0, ix1 = [int(np.argmin(np.abs(axis - q))) for q in (x0, x1)] + iy0, iy1 = [int(np.argmin(np.abs(axis - q))) for q in (y0, y1)] + sx, sy, k = slice(ix0, ix1 + 1), slice(iy0, iy1 + 1), fw.z0_index(Z) + along_x = (fw.line_integral(Ax[sx, iy0, k], dx) + - fw.line_integral(Ax[sx, iy1, k], dx)) + along_y = ___ + return along_x + along_y + + +# RIGHT SIDE. n-hat is +z-hat, so only the z-component of the curl crosses the +# rectangle. Integrate it over the flat patch the same indices span: one call +# to fw.area_integral, on the z = 0 plane, with spacings dx and dy. + +def curl_flux(x0, x1, y0, y1): + """Flux of the vorticity through the same rectangle: Stokes' right side.""" + ix0, ix1 = [int(np.argmin(np.abs(axis - q))) for q in (x0, x1)] + iy0, iy1 = [int(np.argmin(np.abs(axis - q))) for q in (y0, y1)] + return ___ + + +# --- given: the limit in the definition, run as a measurement. Every side +# below is a whole number of grid spacings, so each loop is the one asked +# for rather than the nearest one the grid happens to be able to draw. +def curl_z_area(A, x0, x1, y0, y1): + """Circulation per unit area round the same rectangle.""" + return loop_circulation(A[0], A[1], x0, x1, y0, y1) / ((x1 - x0) * (y1 - y0)) + +w_centre = curl_oseen[2][c, c, fw.z0_index(Z)] +print(f"vorticity at the origin: measured {w_centre:.4f} s^-1, " + f"exact {Gamma/(np.pi*b_core**2):.4f} s^-1") +print(f"the whole Gaussian, worst error " + f"{np.abs(curl_oseen[2] - w_exact)[interior].max()/w_exact.max():.2%} of peak\n") +print(f"{'side [m]':>9} {'samples/edge':>13} {'circulation':>13} {'C/A':>9}" + f" {'C/A / measured':>15}") +for m in (18, 9, 6, 3, 2, 1): + h = m * dx + print(f"{2*h:9.4f} {2*m+1:13d} {loop_circulation(*oseen[:2], -h, h, -h, h):13.5f}" + f" {curl_z_area(oseen, -h, h, -h, h):9.4f}" + f" {curl_z_area(oseen, -h, h, -h, h)/w_centre:15.4f}") + +# --- given: Stokes' theorem on five rectangles, two of them off-centre --- +rects = [("centred, side 0.8", (-0.4, 0.4, -0.4, 0.4)), + ("centred, side 2.0", (-1.0, 1.0, -1.0, 1.0)), + ("centred, side 3.2", (-1.6, 1.6, -1.6, 1.6)), + ("off-centre, over the core", (-0.2, 1.4, -0.6, 1.0)), + ("off to one side", (0.4, 1.6, -0.6, 0.6))] +print(f"\n {'rectangle':<26} {'circulation':>12} {'flux of curl':>13} {'apart':>8}") +for name, lim in rects: + C, S = loop_circulation(*oseen[:2], *lim), curl_flux(*lim) + print(f" {name:<26} {C:12.5f} {S:13.5f} {abs(C - S)/abs(C):8.2%}") +print(f"\n all the vorticity there is: Gamma = {Gamma:.4f} m^2/s") + +fig, axes = plt.subplots(1, 3, figsize=(16, 4.2)) +fw.show_field_slice(X, Y, Z, *oseen[:2], background=curl_oseen[2], ax=axes[0], + density=1.2, vmin=0, vmax=1.3, levels=14, cmap="inferno", + symmetric=False, stream_color="w", + label=r"$(\nabla\times\mathbf{v})_z$ [s$^{-1}$]", + title="the vortex, over its vorticity") +prof = np.linspace(1e-3, 2.0, 400) +axes[1].plot(prof, Gamma/(2*np.pi*prof)*(1 - np.exp(-prof**2/b_core**2)), "k", lw=1.8, + label=r"$v_\phi(\varrho)$") +axes[1].plot(prof, Gamma*prof/(2*np.pi*b_core**2), "C1--", lw=1.2, + label=r"core: $\Gamma\varrho/2\pi b^2$") +axes[1].plot(prof, Gamma/(2*np.pi*prof), "C2:", lw=1.4, label=r"outside: $\Gamma/2\pi\varrho$") +axes[1].set_ylim(0, 0.25); axes[1].set_title(r"rigid inside the core, $1/\varrho$ outside") +axes[1].set_xlabel(r"$\varrho$ [m]"); axes[1].set_ylabel(r"$v_\phi$ [m s$^{-1}$]") + +# the claim under test, drawn: measured vorticity against the exact Gaussian +k0 = fw.z0_index(Z) +axes[2].plot(X[:, c, k0], w_exact[:, c, k0], "k", lw=2.4, alpha=0.35, label="exact") +axes[2].plot(X[:, c, k0], curl_oseen[2][:, c, k0], "C3", lw=1.2, label="measured") +axes[2].set_ylim(0, 1.45); axes[2].set_title("vorticity along $y = 0$") +axes[2].set_xlabel("$x$ [m]"); axes[2].set_ylabel(r"$(\nabla\times\mathbf{v})_z$ [s$^{-1}$]") +for ax_ in axes[1:]: + ax_.axvline(b_core, color="C0", lw=1, alpha=0.6) + ax_.grid(alpha=0.3); ax_.legend(fontsize=8) +axes[1].annotate(r"$\varrho = b$", (b_core + 0.05, 0.02), color="C0", ha="left") +plt.tight_layout() +plt.show() + +# --- self-check (leave this alone) --- +_h = 6 * dx +fw.check_scalar("Stokes: circulation = flux of the curl through the loop", + loop_circulation(*oseen[:2], -_h, _h, -_h, _h), + curl_flux(-_h, _h, -_h, _h), rtol=0.01, unit=" m^2/s") +fw.check_scalar("...and again on a rectangle that is not centred on the vortex", + loop_circulation(*oseen[:2], -0.2, 1.4, -0.6, 1.0), + curl_flux(-0.2, 1.4, -0.6, 1.0), rtol=0.01, unit=" m^2/s") +_small = curl_z_area(oseen, -dx, dx, -dx, dx) +fw.check(f"circulation per unit area -> the vorticity at the centre " + f"({_small:.4f} against {w_centre:.4f} s^-1)", + abs(_small - w_centre) < 0.01 * abs(w_centre)) +_wide = loop_circulation(*oseen[:2], -1.6, 1.6, -1.6, 1.6) +fw.check(f"a loop well outside the core collects all of Gamma " + f"({_wide:.4f} of {Gamma:.4f} m^2/s)", abs(_wide - Gamma) < 0.01 * Gamma) +``` + +:::{admonition} Solution — Task 8 +:class: dropdown + +```python +# in loop_circulation, the left side: + along_y = (fw.line_integral(Ay[ix1, sy, k], dy) + - fw.line_integral(Ay[ix0, sy, k], dy)) + +# in curl_flux, the right side: + return fw.area_integral(curl_oseen[2][ix0:ix1+1, iy0:iy1+1, fw.z0_index(Z)], + dx, dy) +``` +::: + +:::{admonition} The same theorem, one dimension down +:class: important + +Read the first table downwards. The loop shrinks, the circulation falls, the area falls faster, and the ratio climbs to 0.996 of the vorticity measured at the centre: 0.137 of it at side 2.4 m, 0.908 at side 0.4 m. That is the limit in the definition, evaluated rather than asserted. The comparison is against the **measured** 1.2620 s$^{-1}$ rather than the exact 1.2732, so the last 0.9% is the grid error already reported above and not a failure of the limit. + +Read the second table across. Five rectangles, two of them not centred on the vortex, and the two sides of Stokes' theorem agree to better than 1% on every one: to a few parts in $10^{5}$ on the largest centred loop, and worst on the smallest, which is only 13 samples across. Size, not placement, is what sets the accuracy, and it is the same second-order error Task 5 measured on the divergence theorem. The left side never looks inside the loop and the right side never looks at the boundary. + +| | Divergence theorem | Stokes' theorem | +| :--- | :--- | :--- | +| Boundary integral | flux through a closed **surface** | circulation round a closed **curve** | +| Interior integral | $\nabla\cdot\boldsymbol{v}$ over the enclosed **volume** | $\hat{\boldsymbol{n}}\cdot(\nabla\times\boldsymbol{v})$ over the enclosed **area** | +| Source it counts | $Q_{\text{enc}}/\varepsilon_0$ | $\Gamma$, or the enclosed current | + +The largest loop returns 0.9999 of $\Gamma$, exactly as the largest boxes of Task 5 weighed the whole 1 nC. Enlarging a loop that already encloses all the vorticity adds nothing, for the same reason that charge outside a closed surface contributes nothing. +::: + +### The wire, and Ampère's law + +Shrink the vortex core to nothing, $b\to 0$, and $v_\phi$ becomes the irrotational $\Gamma/2\pi\varrho$ of Task 7 at every radius, with all the vorticity compressed onto the axis. The Gaussian collapses to a Dirac delta, as the Gaussian blob of charge did when Part 2 shrank it to a point. + +That field is the magnetic field of a straight wire carrying a current $I$ along $\hat{\boldsymbol{z}}$, and the statement relating them is **Ampère's law**, in the differential and integral forms Stokes' theorem connects: + +$$ \nabla\times\boldsymbol{H} = \boldsymbol{J} \qquad\Longleftrightarrow\qquad \oint_{\boldsymbol{r}}\boldsymbol{\tau}\cdot\boldsymbol{H}\;dl = \int_{\boldsymbol{r}\in S}\hat{\boldsymbol{n}}\cdot\boldsymbol{J}\;dS = I_{\text{enc}} $$ + +with $\boldsymbol{H}$ in A/m, $\boldsymbol{J}$ in A/m$^2$, and $\hat{\boldsymbol{n}}$ fixed by the right-hand rule from the direction of travel. `loop_circulation` walks counter-clockwise in the $z=0$ plane, so $\hat{\boldsymbol{n}} = \hat{\boldsymbol{z}}$ and a positive answer means current flowing towards the reader. + +```{code-cell} ipython3 +I_wire = 1.0 # current along +z, in amperes +Hx, Hy = -Y * I_wire / (2*np.pi*varrho_s**2), X * I_wire / (2*np.pi*varrho_s**2) + +print(f" {'loop':<28} {'oint tau.H dl [A]':>18}") +for name, lim in [("encloses the wire, side 0.8", (-0.4, 0.4, -0.4, 0.4)), + ("encloses the wire, side 2.0", (-1.0, 1.0, -1.0, 1.0)), + ("encloses the wire, side 3.2", (-1.6, 1.6, -1.6, 1.6)), + ("encloses it, lopsidedly ", (-0.4, 1.6, -1.0, 0.6)), + ("misses the wire ", (0.4, 1.6, -0.6, 0.6)), + ("misses it, and is large ", (0.2, 1.8, -1.8, 1.8))]: + print(f" {name:<28} {loop_circulation(Hx, Hy, *lim):18.5f}") +print(f"\n current actually in the wire: {I_wire:.5f} A") +``` + +:::{admonition} A loop that encloses nothing measurable +:class: important + +Every loop enclosing the wire returns $I$ to better than two parts in a thousand, at any size and whether or not it is centred on the wire. Every loop missing it returns at most $4\times10^{-4}$ A, which against the enclosing loops' 1 A is zero. The circulation counts what passes through the loop and nothing else, exactly as the closed surface of Part 2 counted the charge inside and nothing else. Shape-independence is part of the same statement, though `loop_circulation` draws only rectangles and cannot demonstrate it; it follows from Stokes' theorem, since two loops enclosing the same current bound surfaces carrying the same flux of $\boldsymbol{J}$. + +Now put that beside Task 7. At every point these loops pass through, $\nabla\times\boldsymbol{H} = 0$: the field is irrotational everywhere the grid can sample it, and the loop integral is 1 A regardless. There is no contradiction. Stokes' theorem equates the circulation to the flux of $\boldsymbol{J}$ through the loop, and $\boldsymbol{J}$ is zero over the whole of the loop's interior except one line, where it is infinite. The current density is a Dirac delta on the axis, the integral form survives it, and the differential form does not, which is what happened to $\rho_v$ at the point charge in Part 2. + +A real wire has a finite radius and a finite $\boldsymbol{J}$ spread over its cross-section, and then both forms hold everywhere. The homework builds that wire. +::: + +### Why the electric fields had a potential + +$\boldsymbol{E} = -\nabla V$ was written in Lab 1 without asking whether an arbitrary vector field can be written that way. The rotation, the shear and the vortex above cannot. The curl is the test: + +$$ \nabla\times\left(\nabla p\right) = \boldsymbol{0} \qquad \text{for every twice-differentiable } p $$ + +because each component subtracts a pair of mixed second derivatives, $\partial_x\partial_y p - \partial_y\partial_x p$, and mixed partials commute. Run the two electric fields of this notebook through the curl. + +```{code-cell} ipython3 +E_point = tuple(np.nan_to_num(q) for q in (Ex, Ey, Ez)) # built as -grad V +curl_point = curl(*E_point, dx, dy, dz) +curl_blob = curl(Ex_b, Ey_b, Ez_b, dx, dy, dz) # built from E_r(r) r-hat + +shell = interior & (r > 0.5) & (r < 1.6) +for name, w, A in [("point charge, from -grad V", curl_point, E_point), + ("blob, from the analytic E_r", curl_blob, (Ex_b, Ey_b, Ez_b))]: + # index first: |E| is zero inside the mask, and 0/0 there would warn + wm = np.sqrt(w[0]**2 + w[1]**2 + w[2]**2)[shell] + Am = (np.sqrt(A[0]**2 + A[1]**2 + A[2]**2) / rs)[shell] + print(f" {name:28s} median |curl E| / (|E|/r) = {np.median(wm / Am):.2e}") + +# The circulation, on the blob field, which carries no mask for a loop to cross. +# Reported against the natural scale for a voltage here: the strongest field on +# the grid, carried along one metre of path. +scale_V = float(np.max(np.sqrt(Ex_b**2 + Ey_b**2 + Ez_b**2))) +print(f"\n {'loop':<20} {'circulation of E':>18} {'/ (|E|max x 1 m)':>18}") +for name, lim in [("centred, side 2.0", (-1.0, 1.0, -1.0, 1.0)), + ("off-centre", (-0.2, 1.4, -0.6, 1.0)), + ("off to one side", (0.4, 1.6, -0.6, 0.6))]: + circ = loop_circulation(Ex_b, Ey_b, *lim) + print(f" {name:<20} {circ:+15.2e} V {abs(circ)/scale_V:18.1e}") +print(f"\n the same square, side 2.0, on the wire above: " + f"{loop_circulation(Hx, Hy, -1.0, 1.0, -1.0, 1.0):.3f} A") +``` + +:::{admonition} Why voltage is a number and not a route +:class: important + +The two fields report zero curl with thirteen orders of magnitude between them, and the gap is in how each was built rather than in the physics. `Ex, Ey, Ez` came out of `-np.gradient(V)`, and the curl subtracts the same centred differences in the opposite order; the stencil obeys the identity as strictly as the algebra does, so nothing survives but the order in which floating-point numbers were added, around $10^{-16}$. The blob field was built from the analytic $E_r(r)$ and never passed through a numerical gradient, so it shows the 0.6% that a centred difference costs on this grid. Neither number measures the physics. Both are consistent with the one statement being tested. + +The circulations say the same thing on a closed curve: a few parts in $10^{4}$ of the natural voltage scale, dropping to round-off on the centred loop, whose symmetry cancels it exactly. Put the last line beside them. Same integrator, same grid, same size of loop, and the wire returns a full ampere. + +Zero circulation is what makes potential a usable idea. Carrying a charge round a circuit and back to its starting point costs no net work, so the work done between two points is independent of the route, and one number can be attached to each point. That number is $V$. + +Two restrictions are worth naming, and Part 3 has already demonstrated both. + +**Zero curl gives a potential only where the region has no holes in it.** The wire is the exception: $\nabla\times\boldsymbol{H} = \boldsymbol{0}$ at every point outside it, and $\oint\boldsymbol{\tau}\cdot\boldsymbol{H}\,dl = I \neq 0$. A loop encircling the axis cannot be shrunk to a point without crossing the current, so there is nothing for Stokes' theorem to integrate the curl over, and no single-valued potential for $\boldsymbol{H}$ exists out there. Around a point charge, by contrast, the punctured space *is* simply connected and $V$ survives. + +**$\nabla\times\boldsymbol{E} = \boldsymbol{0}$ holds in electrostatics.** When the magnetic field changes with time, $\nabla\times\boldsymbol{E} = -\partial\boldsymbol{B}/\partial t$, the circulation round a loop is no longer zero, and that circulation is the voltage a generator produces. At that point $V$ alone stops being enough, which is where this course is going. ::: --- ## Closing -The chain built in this lab, in one line: +The chain built across the two labs, in one line: + +$$ \rho_v \;\longrightarrow\; V \;\xrightarrow{\ -\nabla\ }\; \boldsymbol{E} \;\xrightarrow{\ \nabla\cdot\ }\; \rho_v/\varepsilon_0, \qquad \nabla\times\boldsymbol{E} = \boldsymbol{0} $$ -$$ \rho_v \;\longrightarrow\; V \;\xrightarrow{\ -\nabla\ }\; \boldsymbol{E} \;\xrightarrow{\ \nabla\cdot\ }\; \rho_v/\varepsilon_0 $$ +with the last statement the licence for the arrow labelled $-\nabla$: only a field with zero curl has a potential to be recovered from. - **Gradient.** Scalar in, vector out. Points along steepest increase, normal to the level surfaces, with length equal to the rate of increase. - **Divergence.** Vector in, scalar out. Net flux per unit volume, which measures what is created at a point and nothing else. +- **Curl.** Vector in, vector out. Net circulation per unit area, about the axis its own direction gives, which measures local rotation and not the shape of a streamline. -### The same two operators, elsewhere in ECT +Each of the last two comes with an integral theorem, and each theorem replaces a derivative that fails at a singular source with an integral that does not. The point charge and the current-carrying wire are the same difficulty met twice. -Electrostatics is a convenient place to learn this pair, not the only place to use it. Each row below gives a potential, its gradient, and a statement about sources. The numerical machinery written in this lab applies unchanged to all of them: +### The same three operators, elsewhere in ECT + +Electrostatics is a convenient place to learn these, not the only place to use them. Each row below gives a potential, its gradient, and a statement about sources. The numerical machinery written in these two labs applies unchanged to all of them: | System | Potential | Field | Source equation | | :--- | :--- | :--- | :--- | @@ -820,15 +1271,19 @@ Electrostatics is a convenient place to learn this pair, not the only place to u | Heat conduction | $T$ [K] | $\boldsymbol{q}_T = -k\nabla T$   [W/m$^2$] | $\nabla\cdot\boldsymbol{q}_T = 0$ (steady, no sources) | | Groundwater flow | $h$ [m] | $\boldsymbol{q}_h = -K\nabla h$   [m/s] | $\nabla\cdot\boldsymbol{q}_h = 0$ (steady, incompressible) | -with $k$ the thermal conductivity [W m$^{-1}$ K$^{-1}$] and $K$ the hydraulic conductivity [m/s]. +with $G$ the gravitational constant, $\rho_m$ the mass density [kg m$^{-3}$], $k$ the thermal conductivity [W m$^{-1}$ K$^{-1}$] and $K$ the hydraulic conductivity [m/s]. The minus signs are all the same minus sign: heat flows from hot to cold, water flows from high head to low, a positive charge falls from high potential to low. Flow runs downhill, and the gradient points uphill. -The last two rows show why solenoidal fields matter in practice. $\nabla\cdot\boldsymbol{q} = 0$ in an aquifer is not an approximation of convenience; it is conservation of water written locally. +The last two rows show why solenoidal fields matter in practice. $\nabla\cdot\boldsymbol{q}_h = 0$ in an aquifer states conservation of water locally, in the form a numerical model actually solves. -### Homework +In a **homogeneous** medium, where $k$ and $K$ are constants, every field in that table is a gradient, so every one of them has zero curl and none can circulate. Let $K$ vary from place to place, as it does in any real aquifer, and $\nabla\times\boldsymbol{q}_h = -\nabla K\times\nabla h$ need not vanish. The fields that circulate are the ones with no potential to be had, and they are the subject of the rest of the course: -The exercises in the lecture notes are the written homework. Below is the lab's computational extension, which carries the same two operators into a different physical system. +| Field | Circulation equation | What sets it | +| :--- | :--- | :--- | +| Magnetic field $\boldsymbol{H}$ [A/m] | $\nabla\times\boldsymbol{H} = \boldsymbol{J}$ | the current threading the loop | +| Fluid velocity $\boldsymbol{v}$ [m/s] | $\nabla\times\boldsymbol{v} = \boldsymbol{\omega}_v$ | shear at a boundary, and rotation of the Earth | +| Electric field, unsteady | $\nabla\times\boldsymbol{E} = -\partial\boldsymbol{B}/\partial t$ | a magnetic field that changes with time | **A heat source in a room.** Replace the spherical blob with a flat rectangular heater, $1.0 \times 0.6$ m in the $z = 0$ plane. A steady point source of power $P$ in a medium of conductivity $k$ raises the temperature above ambient by $P/4\pi k r$, the same $1/r$ used throughout this lab. Split the plate into $N = 20 \times 12$ sub-sources, give each an equal share $P/N$ of the power, and superpose them as two charges were superposed in Lab 1's Task 8: From b58ea19e6929c3fc3f018e1ec8fbab467f2de3d1 Mon Sep 17 00:00:00 2001 From: ARS183 <1028762817@qq.com> Date: Wed, 2 Sep 2026 18:37:51 +0200 Subject: [PATCH 16/17] Replace the homework with a formative assessment on both chapters --- .../labs/week02_div_curl.md | 197 +++++++++++++++++- 1 file changed, 190 insertions(+), 7 deletions(-) diff --git a/book/1_gradient_divergence_curl/labs/week02_div_curl.md b/book/1_gradient_divergence_curl/labs/week02_div_curl.md index a4deeb5..ac0e3df 100644 --- a/book/1_gradient_divergence_curl/labs/week02_div_curl.md +++ b/book/1_gradient_divergence_curl/labs/week02_div_curl.md @@ -1285,13 +1285,196 @@ In a **homogeneous** medium, where $k$ and $K$ are constants, every field in tha | Fluid velocity $\boldsymbol{v}$ [m/s] | $\nabla\times\boldsymbol{v} = \boldsymbol{\omega}_v$ | shear at a boundary, and rotation of the Earth | | Electric field, unsteady | $\nabla\times\boldsymbol{E} = -\partial\boldsymbol{B}/\partial t$ | a magnetic field that changes with time | -**A heat source in a room.** Replace the spherical blob with a flat rectangular heater, $1.0 \times 0.6$ m in the $z = 0$ plane. A steady point source of power $P$ in a medium of conductivity $k$ raises the temperature above ambient by $P/4\pi k r$, the same $1/r$ used throughout this lab. Split the plate into $N = 20 \times 12$ sub-sources, give each an equal share $P/N$ of the power, and superpose them as two charges were superposed in Lab 1's Task 8: +where $\boldsymbol{\omega}_v \equiv \nabla\times\boldsymbol{v} = 2\boldsymbol{\omega}$ is the vorticity, twice the local angular velocity of Task 6. -$$ T(\boldsymbol{r}) = \frac{P}{4\pi k N}\sum_{i=1}^{N} \frac{1}{\lvert \boldsymbol{r} - \boldsymbol{r}_i \rvert}, \qquad P = 100\ \text{W}, \qquad k_{\text{air}} = 0.026\ \text{W m}^{-1}\text{K}^{-1}. $$ +The first row is Ampère's law in the static limit, and the term Maxwell added to it, $\partial\boldsymbol{D}/\partial t$, is the reason light exists. The third is Faraday's law, where the potential $V$ stops being sufficient on its own. Those two together with the two source equations of Parts 1 and 2 are Maxwell's four. -Check the dimensions before coding: $[P]/[k] = \text{W}/(\text{W m}^{-1}\text{K}^{-1}) = \text{m}\cdot\text{K}$, divided by a distance, so $T$ comes out in kelvin. A temperature formula that does not reduce to kelvin contains an error. Then: +### Formative assessment — Chapters 1 and 2 -- Plot the isosurfaces. Close to the plate they should be rounded rectangles; far away they should become spheres. Explain why the shape loses the imprint of its source. -- Compute the heat flux $\boldsymbol{q}_T = -k\nabla T$, with the same minus sign and the same reason as $\boldsymbol{E} = -\nabla V$. -- Check that $\nabla\cdot\boldsymbol{q}_T \approx 0$ away from the heater, and that the closed-surface flux through a box containing the plate is *not* zero. State what each result means physically for a room at steady state, and which of the two fields in Task 2 the heater resembles. -- **Then examine the number.** One metre from a 100 W panel this model predicts about $+290$ K above ambient, a room at 300 °C. The arithmetic is correct, so the physics is wrong. Identify the failed assumption; two are worth naming, namely what actually transports heat through air, and where this solution places the walls of the room. Re-running with $k = 1.5$ W m⁻¹K⁻¹, the conductivity of soil, gives $+5$ K: the same equations now describe a buried heating element, a problem that pure conduction does solve. +Not graded, and not handed in. It exists so you can find out what you do not yet know, while there is still time to fix it. Allow about **45 minutes**: 12 for Part A and the rest for Part B. + +The two chapters end here. Part A checks that you can say what the operators mean; Part B gives you a system nobody has solved for you and asks you to measure all three. + +#### Part A — six questions, no code + +:::{admonition} A1. Summing and truncating +:class: tip + +The bouncing ball converged: every extra term in $\sum T_n$ brought the answer closer to $T_\infty$. The series for $(1+x)^{-1}$ did not, once $\lvert x\rvert > 1$: no number of terms helps. Both are infinite sums of shrinking-looking terms. What distinguishes them, and how would you decide which case you are in before spending an afternoon adding terms? +::: + +:::{admonition} A2. Which coordinates, and which symbol +:class: tip + +You are handed three fields: the temperature around a buried sphere; the magnetic field around a long straight cable; the field in a rectangular room. Which coordinate system would you compute each in, and why? Then: in cylindrical coordinates the radial distance is written $\varrho$ and in spherical it is written $r$. Give one calculation that goes wrong if you conflate them. +::: + +:::{admonition} A3. The gradient of a distance +:class: tip + +Without computing anything: what is $\lvert\nabla r\rvert$, and why must it be that number for every $r > 0$? What direction does $\nabla r$ point, and what does that say about the surfaces $r = \text{constant}$? +::: + +:::{admonition} A4. Two fields that look like sources +:class: tip + +$\boldsymbol{A} = x\,\hat{\boldsymbol{x}} - y\,\hat{\boldsymbol{y}}$ has arrows that fly apart along the $x$-axis, and $\nabla\cdot\boldsymbol{A} = 0$. $\boldsymbol{E}$ outside a charged blob has arrows that fly apart in every direction, and $\nabla\cdot\boldsymbol{E} = 0$ as well. Are these the same statement twice? Explain each with a box, not with algebra. +::: + +:::{admonition} A5. The wire that circulates without curling +:class: tip + +Outside a straight current-carrying wire, $\nabla\times\boldsymbol{H} = \boldsymbol{0}$ at every point you can measure, and yet $\oint\boldsymbol{\tau}\cdot\boldsymbol{H}\,dl = I \neq 0$ around any loop enclosing it. Stokes' theorem says these two are equal. Resolve it. Then say what goes wrong if you try to define a potential for $\boldsymbol{H}$ outside the wire. +::: + +:::{admonition} A6. Why keep both forms +:class: tip + +Each operator came with an integral theorem. Name the one situation, met twice in these labs, in which the differential form fails and the integral form still works, and say what the integral form is doing that the derivative cannot. +::: + +#### Part B — a buried heating panel + +A rectangular electrical heating element, $1.0 \times 0.6$ m, is buried in soil and dissipates $P = 100$ W. Nothing here has been solved for you; the tools are the ones you built. + +A steady point source of power $P$ in a medium of thermal conductivity $k$ raises the temperature above ambient by $P/4\pi k r$, the same $1/r$ used throughout these labs. Split the panel into $N = 20\times12$ sub-sources, give each an equal share of the power, and superpose: + +$$ T(\boldsymbol{r}) = \frac{P}{4\pi k N}\sum_{i=1}^{N}\frac{1}{\lvert\boldsymbol{r}-\boldsymbol{r}_i\rvert}, \qquad P = 100\ \text{W}, \qquad k_{\text{soil}} = 1.5\ \text{W m}^{-1}\text{K}^{-1} $$ + +Check the dimensions before you code. $[P]/[k] = \text{W}/(\text{W m}^{-1}\text{K}^{-1}) = \text{m}\cdot\text{K}$, divided by a distance, so $T$ comes out in kelvin. A temperature formula that does not reduce to kelvin has an error in it. + +```{code-cell} ipython3 +# --- given: the panel, and the grid it sits on (the cube from Part 0) --- +P_heat, k_soil = 100.0, 1.5 # W, and W/m/K for soil +panel_x = np.linspace(-0.5, 0.5, 20) # sub-source positions, in the z = 0 plane +panel_y = np.linspace(-0.3, 0.3, 12) +N_sub = panel_x.size * panel_y.size + +# B1 -- two blanks, inside the loop. `d_min` records how close each grid point +# comes to the nearest sub-source; the mask below uses it. +T_sum = np.zeros_like(X) +d_min = np.full(X.shape, np.inf) +for x0 in panel_x: + for y0 in panel_y: + d = ___ # distance from (x0, y0, 0) to every grid point + d_min = np.minimum(d_min, d) + T_sum += 1.0 / np.maximum(d, 1e-12) +T_panel = ___ # the prefactor, applied once at the end + +# --- given: the panel is a set of singularities, so keep a shell around it --- +T_panel = np.where(d_min < 0.15, np.nan, T_panel) +print(f"{N_sub} sub-sources, each {P_heat/N_sub:.3f} W") +print(f"T ranges {np.nanmin(T_panel):.2f} to {np.nanmax(T_panel):.2f} K above ambient") + +# --- self-check (leave this alone) --- +fw.check_shape("T has the shape of the grid", T_panel, X.shape) +_i1 = int(np.argmin(np.abs(axis - 1.0))) +fw.check_scalar("1 m directly above the centre of the panel", T_panel[c, c, _i1], + 5.007, rtol=0.01, unit=" K") +fw.check("...and the prefactor was applied, not left out", + np.nanmax(T_panel) < 100.0) +``` + +Heat flows down the temperature gradient, with the same minus sign and the same reason as $\boldsymbol{E} = -\nabla V$. Fourier's law is + +$$ \boldsymbol{q}_T = -k\nabla T \qquad [\text{W m}^{-2}] $$ + +and at steady state, away from the panel, no heat is created or destroyed, so $\boldsymbol{q}_T$ should be solenoidal there. It is also a gradient field, so its curl should vanish. + +```{code-cell} ipython3 +# B2 -- three blanks. Reuse the operators you wrote: `divergence` from Task 1 +# and `curl` from Task 6. Both need arrays without NaN, so pass them through +# np.nan_to_num first, as Task 2 did for the dipole. +qx, qy, qz = ___ # Fourier's law, as three arrays +q_T = tuple(np.nan_to_num(v) for v in (qx, qy, qz)) +div_q = ___ +curl_q = ___ + +# --- given: both reported scale-free, against |q|/d, exactly as Task 2 and +# Task 7 did. `far` is the region well clear of the panel. +far = interior & (d_min > 0.6) +q_mag = np.sqrt(q_T[0]**2 + q_T[1]**2 + q_T[2]**2) +yardstick = (q_mag / np.maximum(d_min, 1e-12))[far] +curl_mag = np.sqrt(curl_q[0]**2 + curl_q[1]**2 + curl_q[2]**2) +print(f" |div q| / (|q|/d), away from the panel : " + f"{np.median(np.abs(div_q[far]) / yardstick):.3%}") +print(f" |curl q| / (|q|/d) : " + f"{np.median(curl_mag[far] / yardstick):.2e}") + +# --- self-check (leave this alone) --- +fw.check(f"q points away from the panel, so heat flows outward " + f"({np.median((q_T[0]*X + q_T[1]*Y + q_T[2]*Z)[far]):+.3f})", + np.median((q_T[0]*X + q_T[1]*Y + q_T[2]*Z)[far]) > 0) +fw.check(f"no heat is created away from the panel " + f"({np.median(np.abs(div_q[far]) / yardstick):.2%})", + np.median(np.abs(div_q[far]) / yardstick) < 0.05) +fw.check(f"and the flux of a gradient cannot circulate " + f"({np.median(curl_mag[far] / yardstick):.1e})", + np.median(curl_mag[far] / yardstick) < 1e-10) +``` + +The divergence is zero away from the panel and the panel is certainly a source, so the differential form has nothing to say about how strong it is. Put a closed surface around it instead. `closed_box_flux` from Task 5 works unchanged. + +```{code-cell} ipython3 +# --- given: the divergence theorem as an instrument, reading in watts --- +print(" box half-width power it finds") +for h in (1.0, 1.4): + print(f" {h:.1f} m {closed_box_flux(*q_T, h):8.3f} W") +print(f"\n actually buried {P_heat:8.3f} W") + +# The same box at h = 0.6 m returns 84.3 W. Its faces pass 0.1 m from the edge +# of the panel, inside the shell that was masked out above; np.nan_to_num then +# integrated the deleted samples as zeros. With no mask it returns 100.2 W. +# Question B3 asks what the general rule is. + +# --- self-check (leave this alone) --- +fw.check_scalar("closed-surface flux of q = the power buried inside", + closed_box_flux(*q_T, 1.0), P_heat, rtol=0.01, unit=" W") +fw.check("...and a larger box finds the same power, not more", + abs(closed_box_flux(*q_T, 1.4) - closed_box_flux(*q_T, 1.0)) < 0.01 * P_heat) +``` + +Far from the panel its shape should stop mattering. Test that against the single term a point source would give. + +```{code-cell} ipython3 +# --- given: the panel against one point source of the same total power --- +print(f" {'distance':>10} {'along x':>10} {'along z':>10} {'point source':>14} {'spread':>8}") +for d_ in (0.8, 1.2, 1.6): + i = int(np.argmin(np.abs(axis - d_))) + T_x, T_z = T_panel[i, c, c], T_panel[c, c, i] + print(f" {d_:8.1f} m {T_x:9.3f} K {T_z:9.3f} K " + f"{P_heat/(4*np.pi*k_soil*d_):13.3f} K {abs(T_x-T_z)/T_x:8.1%}") + +# The blank shell in both panels is the masked region, 0.15 m around the +# panel. Its outline in the plan view is the panel's own shape. +fig, axes = plt.subplots(1, 2, figsize=(12.5, 4.6)) +fw.show_field_slice(X, Y, Z, q_T[0], q_T[2], background=T_panel, ax=axes[0], + plane="y", density=1.2, vmin=0, vmax=15, levels=16, + cmap="inferno", symmetric=False, stream_color="w", + label="$T$ above ambient [K]", title="vertical section, $y = 0$") +fw.show_field_slice(X, Y, Z, q_T[0], q_T[1], background=T_panel, ax=axes[1], + plane="z", density=1.2, vmin=0, vmax=15, levels=16, + cmap="inferno", symmetric=False, stream_color="w", + label="$T$ above ambient [K]", title="plan view, $z = 0$") +plt.tight_layout() +plt.show() +``` + +:::{admonition} B3. Four questions on what you just measured +:class: tip + +Answer these in writing. + +1. The closed surface returned 100.05 W and the divergence returned zero everywhere you could measure it. Both are correct. What does each one tell you that the other cannot? +2. The $h = 0.6$ m box returns 84.3 W with the mask in place and 100.2 W without it. State the general rule this illustrates about masked samples and surface integrals. +3. `curl_q` came back at $10^{-15}$ rather than at the fraction of a percent `div_q` shows. Why is it so much smaller, and is that a better measurement or a different kind of statement? +4. In the plan view the isotherms near the panel are rounded rectangles and far away they are circles, and the table shows the difference between the two directions falling from 19% to 5%. What has been lost, and what does that have to do with truncating a series? +::: + +:::{admonition} B4. The number that is wrong +:class: tip + +Everything above was computed in soil, $k = 1.5$ W m⁻¹K⁻¹, and one metre above the panel it predicts $+5.0$ K. Re-run it for the same panel hanging in **air**, $k_{\text{air}} = 0.026$ W m⁻¹K⁻¹. You do not need to recompute anything: $T \propto 1/k$, so the answer is $5.0 \times 1.5/0.026$. + +The arithmetic is right and the answer is absurd. Identify the assumption that failed. Two are worth naming. +::: From dcc7e53a34549cc8a38df41136737a231901bb3b Mon Sep 17 00:00:00 2001 From: ARS183 <1028762817@qq.com> Date: Thu, 3 Sep 2026 22:57:08 +0200 Subject: [PATCH 17/17] Set up the book's title, URLs, editors, schedule and status --- book/0_overview/schedule.md | 59 ++++++++++++++++++++++++++++++++++++- book/_config.yml | 8 ++--- book/changelog.md | 13 +++----- book/credits.md | 17 +++++++---- book/intro.md | 22 ++++++++++++-- 5 files changed, 97 insertions(+), 22 deletions(-) diff --git a/book/0_overview/schedule.md b/book/0_overview/schedule.md index 7552623..7847f84 100644 --- a/book/0_overview/schedule.md +++ b/book/0_overview/schedule.md @@ -1,3 +1,60 @@ # Weekly schedule -Click on the dropdown blocks below to find the schedule of each week's activities. \ No newline at end of file +Each unit runs over one week and consists of three lessons, numbered after the unit. Unit 1.4, for example, is made up of lessons 1.4.1, 1.4.2 and 1.4.3. The first two are lectures and the third is the practical, where the computer labs in this book are used. + +[My Timetable](https://mytimetable.tudelft.nl/) carries the authoritative schedule, with rooms and any changes. + +## Quarter 1 + +| Unit | Topic | Lesson | Date | Time | +| :--- | :--- | :--- | :--- | :--- | +| 1.1 | Gradient and divergence | 1.1.1 | Tue 1 Sep 2026 | 08:45-10:30 | +| | | 1.1.2 | Thu 3 Sep 2026 | 15:45-17:30 | +| | | 1.1.3 | Fri 4 Sep 2026 | 13:45-15:30 | +| 1.2 | Curl | 1.2.1 | Mon 7 Sep 2026 | 10:45-12:30 | +| | | 1.2.2 | Tue 8 Sep 2026 | 13:45-15:30 | +| | | 1.2.3 | Fri 11 Sep 2026 | 13:45-16:30 | +| 1.3 | Potential fields: history and experiments | 1.3.1 | Mon 14 Sep 2026 | 10:45-12:30 | +| | | 1.3.2 | Tue 15 Sep 2026 | 13:45-15:30 | +| | | 1.3.3 | Fri 18 Sep 2026 | 13:45-15:30 | +| 1.4 | Potential fields: gravity, magnetic field of the Earth | 1.4.1 | Mon 21 Sep 2026 | 10:45-12:30 | +| | | 1.4.2 | Tue 22 Sep 2026 | 13:45-15:30 | +| | | 1.4.3 | Fri 25 Sep 2026 | 13:45-16:30 | +| 1.5 | Electric field. Diffusion fields: hot wire | 1.5.1 | Mon 28 Sep 2026 | 10:45-12:30 | +| | | 1.5.2 | Tue 29 Sep 2026 | 13:45-15:30 | +| | | 1.5.3 | Fri 2 Oct 2026 | 13:45-15:30 | +| 1.6 | Diffusion fields: boundary conditions, heat in 2D and 3D | 1.6.1 | Mon 5 Oct 2026 | 10:45-12:30 | +| | | 1.6.2 | Tue 6 Oct 2026 | 15:45-17:30 | +| | | 1.6.3 | Fri 9 Oct 2026 | 13:45-16:30 | +| 1.7 | Mechanical waves: strings, acoustic waves, 2D and 3D | 1.7.1 | Mon 12 Oct 2026 | 10:45-12:30 | +| | | 1.7.2 | Tue 13 Oct 2026 | 13:45-15:30 | +| | | 1.7.3 | Fri 16 Oct 2026 | 13:45-15:30 | +| 1.8 | Mechanical waves: power flux | 1.8.1 | Mon 19 Oct 2026 | 10:45-12:30 | +| | | 1.8.2 | Tue 20 Oct 2026 | 13:45-15:30 | +| | | 1.8.3 | Fri 23 Oct 2026 | 13:45-16:30 | +| 1.9 | Unsupervised study | | | | +| 1.10 | Midterm week: exam and discussion of solutions | 1.10.1 | | | +| | | 1.10.2 | | | +| | | 1.10.3 | Fri 6 Nov 2026 | 13:30-16:30 | + +## Quarter 2 + +| Unit | Topic | Lesson | Date | Time | +| :--- | :--- | :--- | :--- | :--- | +| 2.1 | Electromagnetism: Maxwell's equations, plane waves, telegraph equation | 2.1.1 | Mon 9 Nov 2026 | 13:45-15:30 | +| | | 2.1.2 | Tue 10 Nov 2026 | 13:45-15:30 | +| | | 2.1.3 | Fri 13 Nov 2026 | 10:45-12:30 | +| 2.2 | 3D waves, Poynting vector, polarisation, lossy and lossless media | 2.2.1 | Mon 16 Nov 2026 | 13:45-15:30 | +| | | 2.2.2 | Tue 17 Nov 2026 | 13:45-15:30 | +| | | 2.2.3 | Fri 20 Nov 2026 | 09:45-12:30 | +| 2.3 | Reflection, transmission, refraction. Multi-layered media | 2.3.1 | Mon 23 Nov 2026 | 13:45-15:30 | +| | | 2.3.2 | Tue 24 Nov 2026 | 13:45-15:30 | +| | | 2.3.3 | Fri 27 Nov 2026 | 10:45-12:30 | +| 2.4 | Trapped and surface waves. Phase and group velocity | 2.4.1 | Mon 30 Nov 2026 | 13:45-15:30 | +| | | 2.4.2 | Tue 1 Dec 2026 | 08:45-10:30 | +| | | 2.4.3 | Fri 4 Dec 2026 | 09:45-12:30 | +| 2.8 | Unsupervised study | | | | +| 2.9 | Unsupervised study | | | | +| 2.10 | Resit exam | | Wed 27 Jan 2027 | 13:30-16:30 | + +The exam is on Wed 16 Dec 2026, 13:30-16:30. The longer practicals, running to 16:30, end with a formative assessment. diff --git a/book/_config.yml b/book/_config.yml index 2044f6d..a60db27 100644 --- a/book/_config.yml +++ b/book/_config.yml @@ -2,7 +2,7 @@ # This config includes an opinionated list of configuration options of TeachBooks, Jupyterbook v1, Sphinx and other extensions part of TeachBooks-Favourites. -author: Author from Delft University of Technology, built with TeachBooks, CC BY 4.0 +author: Paco Lopez Dekker, Evert Slob, Guy Drijkoningen and Jinqiang Chen from Delft University of Technology, built with TeachBooks, CC BY 4.0 # Replace TeachBooks Teams with your own name in the line above, configuratin part of JupyterBook: https://jupyterbook.org/en/stable/customize/config.html execute: execute_notebooks: "auto" # Execute notebooks during build when outputs are missing or stale, configuration part of Jupyterbook v1 (https://jupyterbook.org/en/stable/customize/config.html) @@ -27,13 +27,13 @@ sphinx: # Options passed on to the use_thebe_lite: true # Required for live code, part of TeachBooks-Sphinx-Thebe (https://teachbooks.io/manual/features/live_code.html) exclude_patterns: ["**/_*.yml", "**/*.md", "**/*.ipynb"] #exclude files which should not be accessible for live code, configuration part of TeachBooks-Sphinx-Thebe (https://teachbooks.io/manual/features/live_code.html) #html_favicon: # Default value not shown (line can be removed), allows to add your own favicon (disabling of TU Delft favicon is required), configuration part of Sphinx (https://www.sphinx-doc.org/en/master/index.html) - html_baseurl: "https://oit.tudelft.nl>/" # Replace this with your own URL, configuration part of Sphinx (https://www.sphinx-doc.org/en/master/index.html) + html_baseurl: "https://bscect.github.io/FieldWaves/main/" # Replace this with your own URL, configuration part of Sphinx (https://www.sphinx-doc.org/en/master/index.html) html_theme_options: logo: - text: TU Delft GitHub OILM Template # Replace this with your own open interactive learning material title, configuration part of Sphinx (https://www.sphinx-doc.org/en/master/index.html) + text: Fields and Waves # Replace this with your own open interactive learning material title, configuration part of Sphinx (https://www.sphinx-doc.org/en/master/index.html) # image_light: # Default value not shown (line can be removed), adds your logo for the light mode here (can be the same as image_dark) (disabling of TU Delft logo is required), configuration part of Sphinx (https://www.sphinx-doc.org/en/master/index.html) # image_dark: # Default value not shown (line can be removed), adds your logo for the dark mode here (can be the same as image_light) (disabling of TU Delft logo is required), configuration part of Sphinx (https://www.sphinx-doc.org/en/master/index.html) - repository_url: "https://github.com/TUDelft-books/repo" # Add your own repo URL here, configuration part of JupyterBook v1 (https://jupyterbook.org/en/stable/customize/config.html) + repository_url: "https://github.com/BScECT/FieldWaves" # Add your own repo URL here, configuration part of JupyterBook v1 (https://jupyterbook.org/en/stable/customize/config.html) path_to_docs: "book" # Required for edit_page_button, should be book if you're using TeachBooks package (https://github.com/TeachBooks/TeachBooks) or the TeachBooks deploy book workflow (https://teachbooks.io/manual/external/deploy-book-workflow/README.html), configuration part of Jupyterbook v1 (https://jupyterbook.org/en/stable/customize/config.html) repository_branch: "main" # Replace when you change the name of your published branch (required for edit_page_button), configuration part of Jupyterbook v1 (https://jupyterbook.org/en/stable/customize/config.html) use_edit_page_button: true # Replace with false if you don't want the edit page button (i.e. if you don't user to propose changes themselves or have a private repo), configuration part of Jupyterbook v1 (https://jupyterbook.org/en/stable/customize/config.html) diff --git a/book/changelog.md b/book/changelog.md index b9de8fa..8911db5 100644 --- a/book/changelog.md +++ b/book/changelog.md @@ -1,11 +1,6 @@ # Changelog -## ``: `` -- `` [](``) -- ... -- Full Changelog: `[...]()` - -## ``: <...> -- <...> - -<...> +## 2026-09-03 +- Added the Chapter 1 lecture notes: introduction, sums and series, coordinate systems, gradient, divergence and curl. +- Added the two Chapter 1 computer labs, on series and the gradient, and on divergence and curl, with the shared `fwtools` helper module. +- Set the book title, the repository link and the published URL. diff --git a/book/credits.md b/book/credits.md index 2168738..924bdc7 100644 --- a/book/credits.md +++ b/book/credits.md @@ -3,16 +3,16 @@ You can refer to this book as: -> `` from Delft University of Technology (``) _``_. `<url to book website>`. Source files at `<link to github repo`. CC BY 4.0. +> Lopez Dekker, P., Slob, E., Drijkoningen, G. and Chen, J. from Delft University of Technology (2026) _Fields and Waves_. <https://bscect.github.io/FieldWaves/main/>. Source files at <https://github.com/BScECT/FieldWaves>. CC BY 4.0. You can refer to individual chapters or pages within this book as: -> `<Title of Chapter or Page>`. In `<editors>` from Delft University of Technology (`<year>`) _`<title>`_. `<url to specific page on book website>`. Source files at `<link to specific commit / file in github repo`. CC BY 4.0. +> `<Title of Chapter or Page>`. In Lopez Dekker, P., Slob, E., Drijkoningen, G. and Chen, J. from Delft University of Technology (2026) _Fields and Waves_. `<url to specific page on book website>`. Source files at `<link to specific commit / file in github repo>`. CC BY 4.0. We anticipate that the content of this book will change significantly. Therefore, we recommend using the source code directly with the citation above that refers to the GitHub repository and lists the date and name of the file. Although content will be added over time, chapter titles and URL's in this book are expected to remain relatively static. However, we make no guarantee, so if it is important for you to reference a specific location/commit within the book. ## How the book is made -This website is written in markdown and jupyter notebooks files, which are converted to html using tools from [TeachBooks](https://teachbooks.io/). The files are stored on a [public GitHub repository](`<link to GitHub repo>`). The website can be viewed at `<link to book website url>`. +This website is written in markdown and jupyter notebooks files, which are converted to html using tools from [TeachBooks](https://teachbooks.io/). The files are stored on a [public GitHub repository](https://github.com/BScECT/FieldWaves). The website can be viewed at <https://bscect.github.io/FieldWaves/main/>. To recreate the website you have two options (more information in the [TeachBooks manual](https://teachbooks.io/manual/): - In the GitHub interface: fork this repository, enable Github Pages from the source GitHub actions (Settings - Code and automation - Pages - Build and deployment - Source - GitHub Actions), enable workflows (Actions - I understand my workflows, go ahead and enable them) and run the call-deploy-book workflow (Actions - call-deploy-book - Run workflow - Run workflow). The website is released on the URL as shown on the workflow summary when the workflow has finished (Actions - call-deploy-book - call-deploy-book - Summary). @@ -26,7 +26,7 @@ This book is [CC BY 4.0 licensed](https://creativecommons.org/licenses/by/4.0/) Parts of this book are taken from other external resources and reused in various ways. If an author is not listed on a particular page, it is by the Authors, except as follows: -The following pages are included directly from an external resource and is not edited by `<Editor>`: +The following pages are included directly from an external resource and are not edited by the course team: - The following pages includes text from {cite:t}`template`. Original content licensed under CC BY 4.0 License: - [](./exercises.md) - [](./exercises/002.md) @@ -42,7 +42,7 @@ The following pages are included directly from an external resource and is not e - [](./syntax_exercises/011.md) - [](./exercises/summary.md) -The following pages contain content written by others, part of has been reused and/or modified by `<Editor>` +The following pages contain content written by others, part of which has been reused and/or modified by the course team: - Page [](./exercises/001.md) includes text from {cite:t}`template` and is edited to be made TU Delft-specific. Original content licensed under CC BY 4.0 License. - Page [](./syntax_exercises/012.md) includes text from {cite:t}`template` and is edited to be made TU Delft-specific. Original content licensed under CC BY 4.0 License. @@ -50,4 +50,11 @@ The following pages contain content written by others, part of has been reused a (editor)= ## About the Editors +This book is written and maintained by the ECTB2140 teaching team at Delft University of Technology: + +- **Paco Lopez Dekker**, Department of Space Engineering, Faculty of Aerospace Engineering +- **Evert Slob**, Department of Geoscience and Engineering, Faculty of Civil Engineering and Geosciences +- **Guy Drijkoningen**, Department of Geoscience and Engineering, Faculty of Civil Engineering and Geosciences +- **Jinqiang Chen**, Department of Geoscience and Engineering, Faculty of Civil Engineering and Geosciences + ### Acknowledgements diff --git a/book/intro.md b/book/intro.md index 1b99fce..400ed64 100644 --- a/book/intro.md +++ b/book/intro.md @@ -4,12 +4,28 @@ title: ECTB2140 Fields and Waves 2026 # Fields and Waves +:::{admonition} This book is under development +:class: warning + +The book is being written during the 2026-2027 run of ECTB2140, and the material is incomplete beyond the first chapter. + +- **Chapter 1, Gradient, divergence and curl**, is complete: the lecture notes and both computer labs. +- **Chapter 2, Potential fields**, is partly written. +- Later chapters are not yet available here. +- The **Exercises** section in the sidebar is left over from the book template. It explains how TeachBooks works and is not course material. + +Brightspace remains the authoritative source for the schedule, assessment and announcements. Pages here change between weeks, so download a notebook again rather than relying on a copy saved earlier. +::: + ## Course description Physical objects can be described in a quantitative way only with the aid of mathematics. In classical physics, all physical objects are geometric objects. The course “Fields and Waves” combines the physics of fields and waves with the mathematical tools required to describe these phenomena. The course enables students to develop the essential understanding of the physical interpretation of mathematical formulations. Examples are radar waves that are used for earth surface and subsurface observations from antennas placed on satellites, airplanes, and close to or on the ground surface; sound waves, electromagnetic diffusion fields, electric and magnetic potential fields, and the gravity field to probe the earth’s interior. The approach is to start with relevant physical problems (1D wave equation, stretched membrane, electrostatic fields, heat diffusion, 2D and 3D waves) introducing mathematical tools and concepts (Partial Differential Equations (elliptic, parabolic, hyperbolic), separation of variables, Fourier series and Fourier transformations) during the course as needed to solve specific problems. While being able to find solutions for some specific cases is an important part of the course, the emphasis of the course is on learning how to describe the relevant physics with the corresponding math, to understand the solution space, and to be able to interpret solutions. -### Expected prior knowledge: -... +### Expected prior knowledge + +- Calculus +- Mechanics and Thermodynamics +- Linear Algebra ## What to expect? <!-- This Jupyter book provides the road map for the course. All activities are introduced in the following chapters and there are a number of assignments you need to do. The didactic approach is based on guided tutorials where you study and practice the material yourself. The amount of lectures is kept to a minimum. In order to benefit most from this style of learning we urge you to prepare each lecture. We have scheduled time for this preparation in the time planner. @@ -20,4 +36,4 @@ Brightspace will be used for providing day to day information relevant to this c -<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a> \ No newline at end of file +<a rel="license" href="https://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by/4.0/88x31.png" /></a> \ No newline at end of file