Beam Class Regression Tests¶
%load_ext autoreload
%autoreload 2
import numpy as np
from distgen import Generator
from distgen.physical_constants import PHYSICAL_CONSTANTS
from distgen.tools import check_abs_and_rel_tols
from glob import glob
yaml_files = list(glob("../examples/data/*.yaml"))
coordinates = {
    "x",
    "y",
    "z",
    "px",
    "py",
    "pz",
    "r",
    "theta",
    "pr",
    "ptheta",
    "xp",
    "yp",
    "thetax",
    "thetay",
    "gamma",
    "energy",
    "kinetic_energy",
    "beta_x",
    "beta_y",
    "beta_z",
}
def run_test_on_input_file(input_file, test):
    G = Generator(input_file, verbose=0)
    G["n_particle"] = 10_000
    test(G.beam())
def run_test_on_input_files(input_files, test, verbose=False):
    for input_file in input_files:
        if verbose:
            print("Testing:", input_file)
        run_test_on_input_file(input_file, test)
Statistical Tests¶
$\sum_i w_i = 1$
def test_weight_normalization(beam):
    check_abs_and_rel_tols(
        "macroparticle weights", np.sum(beam["w"]), 1.0, abs_tol=1e-12, rel_tol=1e-15
    )
run_test_on_input_files(yaml_files, test_weight_normalization)
$\langle \mathcal{O}\rangle = \sum_i w_i \mathcal{O}_i$
def test_avg(beam):
    for var in coordinates:
        avg_beam, avg_numpy = beam.avg(var), np.sum(beam["w"] * beam[var])
        check_abs_and_rel_tols(
            "beam.avg", avg_beam, avg_numpy, abs_tol=1e-12, rel_tol=1e-15
        )
run_test_on_input_files(yaml_files, test_avg)
$\sigma_{\mathcal{O}}^2 = \sum_i w_i (\mathcal{O}_i-\langle \mathcal{O}\rangle)^2 $
def test_std(beam):
    for var in coordinates:
        sigma2_beam = beam.std(var) ** 2
        sigma2_numpy = np.sum(beam["w"] * (beam[var] - beam.avg(var)) ** 2)
        check_abs_and_rel_tols(
            "beam.std", sigma2_beam, sigma2_numpy, abs_tol=1e-8, rel_tol=1e-15
        )
run_test_on_input_files(yaml_files, test_std)
$r=\sqrt{ x^2 + y^2 }$
def test_r(beam):
    check_abs_and_rel_tols(
        "beam.r",
        beam["r"],
        np.sqrt(beam["x"] ** 2 + beam["y"] ** 2),
        abs_tol=1e-15,
        rel_tol=1e-15,
    )
run_test_on_input_files(yaml_files, test_r)
$x=r\cos\theta$
def test_x(beam):
    check_abs_and_rel_tols(
        "beam.x = r cos(theta)",
        beam["x"],
        beam["r"] * np.cos(beam["theta"]),
        abs_tol=1e-12,
        rel_tol=1e-11,
    )
run_test_on_input_files(yaml_files, test_x)
$y = r\sin\theta$
def test_y(beam):
    check_abs_and_rel_tols(
        "beam.y = r sin(theta)",
        beam["y"],
        beam["r"] * np.sin(beam["theta"]),
        abs_tol=1e-12,
        rel_tol=1e-11,
    )
run_test_on_input_files(yaml_files, test_y)
$p_r = p_x\cos\theta + p_y\sin\theta$
def test_pr(beam):
    check_abs_and_rel_tols(
        "beam.pr = px cos(theta) + py sin(theta)",
        beam["pr"],
        beam["px"] * np.cos(beam["theta"]) + beam["py"] * np.sin(beam["theta"]),
        abs_tol=1e-12,
        rel_tol=1e-15,
    )
run_test_on_input_files(yaml_files, test_pr)
$p_{\theta} = -p_x\sin\theta + p_y\cos\theta$
def test_ptheta(beam):
    check_abs_and_rel_tols(
        "beam.ptheta = -px sin(theta) + py cos(theta)",
        beam["ptheta"],
        -beam["px"] * np.sin(beam["theta"]) + beam["py"] * np.cos(beam["theta"]),
        abs_tol=1e-12,
        rel_tol=1e-15,
    )
run_test_on_input_files(yaml_files, test_ptheta)
Transverse Derivatives and Angles¶
Getting¶
$x^{\prime} = p_x/p_z$
def test_xp(beam):
    check_abs_and_rel_tols(
        "beam.xp = px/pz",
        beam["xp"],
        beam["px"].to(beam["pz"].units) / beam["pz"],
        abs_tol=1e-14,
        rel_tol=1e-15,
    )
run_test_on_input_files(yaml_files, test_xp)
$y^{\prime} = p_y/p_z$
def test_yp(beam):
    check_abs_and_rel_tols(
        "beam.yp = py/pz",
        beam["yp"],
        beam["py"].to(beam["pz"].units) / beam["pz"],
        abs_tol=1e-14,
        rel_tol=1e-15,
    )
run_test_on_input_files(yaml_files, test_yp)
$\theta_x = \arctan(p_x/p_z)$
def test_thetax(beam):
    check_abs_and_rel_tols(
        "beam.thetax = arctan(px/pz)",
        beam["thetax"],
        np.arctan2(beam["px"].to(beam["pz"].units), beam["pz"]),
        abs_tol=1e-15,
        rel_tol=1e-15,
    )
run_test_on_input_files(yaml_files, test_thetax)
$\theta_y = \arctan(p_y/p_z)$
def test_thetay(beam):
    check_abs_and_rel_tols(
        "beam.thetay = arctan(py/pz)",
        beam["thetay"],
        np.arctan2(beam["py"].to(beam["pz"].units), beam["pz"]),
        abs_tol=1e-15,
        rel_tol=1e-15,
    )
run_test_on_input_files(yaml_files, test_thetay)
def test_p(beam):
    check_abs_and_rel_tols(
        "beam.p = sqrt(px^2 + py^2 + pz^2)",
        beam["p"],
        np.sqrt(beam["px"] ** 2 + beam["py"] ** 2 + beam["pz"] ** 2),
        abs_tol=1e-15,
        rel_tol=1e-15,
    )
run_test_on_input_files(yaml_files, test_p)
$E = \sqrt{c^2|\vec{p}|^2 + (mc^2)^2}$
def test_energy(beam):
    c = PHYSICAL_CONSTANTS["speed of light in vacuum"]
    check_abs_and_rel_tols(
        "beam.energy = sqrt(c^2p^2 + (mc^2)^2)",
        beam["energy"],
        np.sqrt(c**2 * beam["p"] ** 2 + beam.mc2**2),
        abs_tol=1e-9,
        rel_tol=1e-15,
    )
run_test_on_input_files(yaml_files, test_energy)
$\gamma = \sqrt{1+\left(\frac{p}{mc}\right)^2}$, $E/mc^2$
def test_gamma(beam):
    mc = beam.species_mass * PHYSICAL_CONSTANTS["speed of light in vacuum"]
    check_abs_and_rel_tols(
        "beam.gamma = sqrt( 1 + (p/mc)^2 )",
        beam["gamma"],
        np.sqrt(1 + (beam["p"] / mc).to_reduced_units() ** 2),
        abs_tol=1e-10,
        rel_tol=1e-10,
    )
    check_abs_and_rel_tols(
        "beam.gamma = E/mc^2",
        beam["gamma"],
        beam["energy"] / beam.mc2,
        abs_tol=1e-15,
        rel_tol=1e-15,
    )
run_test_on_input_files(yaml_files, test_gamma)
$\beta = \frac{c|\vec{p}|}{E}$
def test_beta(beam):
    check_abs_and_rel_tols(
        "beam.beta = c|p|/E",
        beam["beta"],
        PHYSICAL_CONSTANTS["speed of light in vacuum"] * beam.p / beam.energy,
        abs_tol=1e-11,
        rel_tol=1e-14,
    )
    assert max(beam["beta"]) < 1, "max(beta) > 1, faster than light particle!"
run_test_on_input_files(yaml_files, test_beta)
$\beta_{x_i} = \frac{cp_{x_i}}{E}$, $\beta_x = x^{\prime}\beta_z$, $\beta_y = y^{\prime}\beta_z$, $\beta_z = \frac{\beta}{\sqrt{1+(x^{\prime})^2 +(y^{\prime})^2}}$
def test_beta_xi(beam):
    for var in ["x", "y", "z"]:
        check_abs_and_rel_tols(
            "beam.beta_xi = c pxi/E )",
            beam[f"beta_{var}"],
            (
                PHYSICAL_CONSTANTS["speed of light in vacuum"]
                * beam[f"p{var}"]
                / beam["energy"]
            ).to_reduced_units(),
            abs_tol=1e-15,
            rel_tol=1e-15,
        )
        check_abs_and_rel_tols(
            "beam.beta_z = sign(pz)*beta/sqrt( 1 + x'^2 + y'^2 )",
            beam["beta_z"],
            np.sign(beam["pz"])
            * beam["beta"]
            / np.sqrt(1 + beam["xp"] ** 2 + beam["yp"] ** 2),
            abs_tol=1e-11,
            rel_tol=5e-9,
        )
run_test_on_input_files(yaml_files, test_beta_xi)
KE = $mc^2(\gamma-1)$, $E-mc^2$
def test_kinetic_energy(beam):
    if PHYSICAL_CONSTANTS.species(beam["species"])["mass"] > 0:
        check_abs_and_rel_tols(
            "beam.kinetic_energy = mc2*(gamma-1)",
            beam["kinetic_energy"],
            beam.mc2 * (beam["gamma"] - 1),
            abs_tol=1e-9,
            rel_tol=1e-05,
        )
    check_abs_and_rel_tols(
        "beam.kinetic_energy = E - mc2",
        beam["kinetic_energy"],
        beam["energy"] - beam.mc2,
        abs_tol=1e-15,
        rel_tol=1e-15,
    )
run_test_on_input_files(yaml_files, test_kinetic_energy)
def test_emitt_normalized(beam):
    for var in ["x", "y"]:
        mc = beam.species_mass * PHYSICAL_CONSTANTS["speed of light in vacuum"]
        stdx = beam.std(var)
        stdp = (beam.std(f"p{var}") / mc).to_reduced_units()
        dx = beam[var] - beam.avg(var)
        dp = ((beam[f"p{var}"] - beam.avg(f"p{var}")) / mc).to_reduced_units()
        check_abs_and_rel_tols(
            "beam.emitt (normalized)",
            beam.emitt(var),
            np.sqrt(stdx**2 * stdp**2 - (np.sum(beam["w"] * dx * dp)) ** 2),
            abs_tol=1e-11,
            rel_tol=1e-11,
        )
run_test_on_input_files(yaml_files, test_emitt_normalized)
$\epsilon_{x} = \sqrt{\sigma_x^2\sigma_{x^{\prime}}^2 - \langle \left(x-\langle x\rangle\right)\left(x^{\prime}-\langle x^{\prime}\rangle\right)\rangle^2 }$
def test_emitt_geometric(beam):
    for var in ["x", "y"]:
        stdx = beam.std(var)
        stdp = beam.std(f"{var}p")
        dx = beam[var] - beam.avg(var)
        dp = beam[f"{var}p"] - beam.avg(f"{var}p")
        check_abs_and_rel_tols(
            "beam.emitt (geometric)",
            beam.emitt(var, "geometric"),
            np.sqrt(stdx**2 * stdp**2 - (np.sum(beam["w"] * dx * dp)) ** 2),
            abs_tol=1e-14,
            rel_tol=1e-15,
        )
run_test_on_input_files(yaml_files, test_emitt_geometric)
Twiss $\beta_{x_i} = \frac{\sigma_x^2}{\epsilon_x}$
def twiss_beta_xi(beam):
    for var in ["x", "y"]:
        stdx = beam.std(var)
        epsx = beam.emitt(var, "geometric")
        if epsx > 0:
            check_abs_and_rel_tols(
                "beam.Beta_xi (Twiss)",
                beam.Beta(var),
                stdx**2 / epsx,
                abs_tol=1e-14,
                rel_tol=1e-15,
            )
run_test_on_input_files(yaml_files, test_beta_xi)
Twiss $\alpha_{x_i} = -\frac{\langle(x-\langle x\rangle)(x^{\prime}-\langle x^{\prime}\rangle)\rangle}{\epsilon_x}$
def test_alpha_xi(beam):
    for var in ["x", "y"]:
        dx = beam[var] - beam.avg(var)
        dp = beam[f"{var}p"] - beam.avg(f"{var}p")
        epsx = beam.emitt(var, "geometric")
        if epsx > 0:
            check_abs_and_rel_tols(
                "beam.Alpha_xi (Twiss)",
                beam.Alpha(var),
                -sum(beam["w"] * dx * dp) / epsx,
                abs_tol=1e-14,
                rel_tol=1e-14,
            )
run_test_on_input_files(yaml_files, test_alpha_xi)
Twiss $\gamma_{x_i} = \frac{\sigma_{x^{\prime}}^2}{\epsilon_x}$
def test_gamma_xi(beam):
    for var in ["x", "y"]:
        stdp = beam.std(f"{var}p")
        epsx = beam.emitt(var, "geometric")
        if epsx > 0:
            check_abs_and_rel_tols(
                "beam.Gamma_xi (Twiss)",
                beam.Gamma(var),
                stdp**2 / epsx,
                abs_tol=1e-14,
                rel_tol=1e-14,
            )
run_test_on_input_files(yaml_files, test_gamma_xi)