axiom

Designing an experiment before there is any data · step 1 of 6

Two atoms, one number

How do you get resolving power against a question nobody has measured?

In 1910 there were two pictures of the atom and no experiment between them. A hard positive centre and a charge smeared through the whole atom both fitted everything anyone had. You cannot design against a debate — so the first move is to find the number the two pictures disagree about.

They are one model at two values of the radius R of the positive charge, six decades apart. An alpha stopped head-on gets no closer than D; one scattered through an angle gets no closer than a known multiple of it; so a charge of radius R kills the scattering past a cut-off angle. Turning the debate into a parameter is what makes everything after this possible.

scattering.py is the case study's own module and it holds the physics: the mean expression, the parameters and their priors, the detector geometry. It is a hand-built ModelSpec rather than anything axiom generates, which is what a problem with real physics in it looks like. The porting tutorial builds the easier kind, a SurfaceSpec, from scratch.

θ 5°45°counter150° radium C′ 7.68 MeV α collimator gold foil 0.4 µm undeflected beam 200,000/s
The apparatus. An alpha source and collimator throw a beam at a gold foil; the counter swings on an arm to the scattering angle theta. The dashed rays are the other stations the plan visits.

closest approach, head-on

D = 2zZe²4πε0E
in axiom
D_CLOSEST = 2 * Z_ALPHA * Z_FOIL * COULOMB_MEV_FM / E_ALPHA * 1e-15
# a constant of the beam and the foil, not a fitted quantity

closest approach at angle θ

rmin(θ) = D2 (1 + 1sin(θ/2))
in axiom
# the floor no amount of counting can beat
floor = S.D_CLOSEST / 2.0

where a charge of radius R kills the tail

sin(θcut/2) = 12R/D − 1   λ = log sin(θcut/2)
in axiom
lam = Param(
    name="lam",
    dimension=dimensionless(),
    prior=Prior(family="normal",
                hyper={"mu": -4.0, "sigma": 6.0}),
)
# the one axis the two atoms are two points on
step 1
import sys
sys.path.insert(0, "nbs/case-studies/rutherford")
import scattering as s

print(f"closest approach D        : {s.D_CLOSEST * 1e15:.1f} fm")
print(f"a hard centre would be    : {s.R_NUCLEUS * 1e15:.1f} fm")
print(f"a diffuse atom would be   : {s.R_ATOM * 1e15:,.0f} fm")
print()
for name, radius in (("hard centre", s.R_NUCLEUS), ("diffuse atom", s.R_ATOM)):
    sine = s.cutoff_sine(radius)
    where = "no cut-off in range" if sine >= 1.0 else f"{sine:.2e}"
    print(f"{name:14s} sin(theta_cut/2) = {where}")
print()
print("the two hypotheses are two values of one parameter, lam:")
print(f"  hard centre  lam = {s.LAM_HARD:+.2f}")
print(f"  diffuse atom lam = {s.LAM_DIFFUSE:+.2f}")

# the numbers the apparatus diagram on this page is drawn from
apparatus = {
    "energy_mev": s.E_ALPHA,
    "d_fm": s.D_CLOSEST * 1e15,
    "foil_um": s.FOIL_THICKNESS * 1e6,
    "beam_per_s": s.BEAM_RATE,
    "angles": [st.theta_deg for st in s.PLAN if st.foil],
}
what it printed
closest approach D        : 59.2 fm
a hard centre would be    : 7.3 fm
a diffuse atom would be   : 135,000 fm

hard centre    sin(theta_cut/2) = no cut-off in range
diffuse atom   sin(theta_cut/2) = 2.19e-04

the two hypotheses are two values of one parameter, lam:
  hard centre  lam = +6.91
  diffuse atom lam = -8.42

Every line above was captured by running this code at build time. The steps share one namespace, so the code on this page is the code you would type after the steps before it.