Source code for mbtrack2.instability.ions

# -*- coding: utf-8 -*-
"""
Various calculations about ion trapping and instabilities in electron storage 
rings.
"""

import matplotlib.pyplot as plt
import numpy as np
from scipy.constants import (
    Boltzmann,
    c,
    e,
    epsilon_0,
    hbar,
    m_e,
    m_p,
    physical_constants,
    pi,
)

rp = 1 / (4*pi*epsilon_0) * e**2 / (m_p * c**2)
re = physical_constants["classical electron radius"][0]


[docs]def ion_cross_section(ring, ion): """ Compute the collisional ionization cross section. Compute the inelastic collision cross section between a molecule or an atom by a relativistic electron using the relativistic Bethe asymptotic formula [1]. Values of M02 and C02 from [2]. Parameters ---------- ring : Synchrotron object ion : str Ion type. Returns ------- sigma : float Cross section in [m**2]. References ---------- [1] : M. Inokuti, "Inelastic collisions of fast charged particles with atoms and molecules-the bethe theory revisited", Reviews of modern physics 43 (1971). [2] : P. F. Tavares, "Bremsstrahlung detection of ions trapped in the EPA electron beam", Part. Accel. 43 (1993). """ if ion == "CO": M02 = 3.7 C0 = 35.1 elif ion == "H2": M02 = 0.7 C0 = 8.1 else: raise NotImplementedError sigma = 4 * pi * (hbar / m_e / c)**2 * ( M02 * (1 / ring.beta**2 * np.log(ring.beta**2 / (1 - ring.beta**2)) - 1) + C0 / ring.beta**2) return sigma
[docs]def ion_frequency(N, Lsep, sigmax, sigmay, ion="CO", dim="y", express="coupling"): """ Compute the ion oscillation frequnecy. Parameters ---------- N : float Number of electrons per bunch. Lsep : float Bunch spacing in [m]. sigmax : float or array Horizontal beam size in [m]. sigmay : float or array Vertical beam size in [m]. ion : str, optional Ion type. The default is "CO". dim : "y" o "x", optional Dimension to consider. The default is "y". express : str, optional Expression to use to compute the ion oscillation frequency. The default is "coupling" corresponding to Gaussian electron and ion distributions with coupling [1]. Also possible is "no_coupling" corresponding to Gaussian electron and ion distributions without coupling [2]. Returns ------- f : float or array Ion oscillation frequencies in [Hz]. References ---------- [1] : T. O. Raubenheimer and F. Zimmermann, "Fast beam-ion instability. I. linear theory and simulations", Physical Review E 52 (1995). [2] : G. V. Stupakov, T. O. Raubenheimer, and F. Zimmermann, "Fast beam-ion instability. II. effect of ion decoherence", Physical Review E 52 (1995). """ if ion == "CO": A = 28 elif ion == "H2": A = 2 elif ion == "CH4": A = 18 elif ion == "H2O": A = 16 elif ion == "CO2": A = 44 if dim == "y": pass elif dim == "x": sigmay, sigmax = sigmax, sigmay else: raise ValueError if express == "coupling": k = 3 / 2 elif express == "no_coupling": k = 1 f = c * np.sqrt(2 * rp * N / (A * k * Lsep * sigmay * (sigmax+sigmay))) / (2*pi) return f
[docs]def fast_beam_ion(ring, Nb, nb, Lsep, sigmax, sigmay, P, T, beta, model="linear", delta_omega=0, ion="CO", dim="y"): """ Compute fast beam ion instability rise time [1]. Warning ! If model="linear", the rise time is an assymptotic grow time (i.e. y ~ exp(sqrt(t/tau))) [1]. If model="decoherence", the rise time is an e-folding time (i.e. y ~ exp(t/tau)) [2]. If model="non-linear", the rise time is a linear growth time (i.e. y ~ t/tau) [3]. The linear model assumes that [1]: x,y << sigmax,sigmay The decoherence model assumes that [2]: Lsep << c / (2 * pi * ion_frequency) Lsep << c / (2 * pi * betatron_frequency) The non-linear model assumes that [3]: x,y >> sigmax,sigmay Parameters ---------- ring : Synchrotron object Nb : float Number of electron per bunch. nb : float Number of bunches. Lsep : float Bunch spacing in [m]. sigmax : float Horizontal beam size in [m]. sigmay : float Vertical beam size in [m]. P : float Partial pressure of the molecular ion in [Pa]. T : float Tempertature in [K]. beta : float Average betatron function around the ring in [m]. model : str, optional If "linear", use [1]. If "decoherence", use [2]. If "non-linear", use [3]. delta_omega : float, optional RMS variation of the ion oscillation angular frequnecy around the ring in [Hz]. ion : str, optional Ion type. The default is "CO". dim : "y" o "x", optional Dimension to consider. The default is "y". Returns ------- tau : float Instability rise time in [s]. References ---------- [1] : T. O. Raubenheimer and F. Zimmermann, "Fast beam-ion instability. I. linear theory and simulations", Physical Review E 52 (1995). [2] : G. V. Stupakov, T. O. Raubenheimer, and F. Zimmermann, "Fast beam-ion instability. II. effect of ion decoherence", Physical Review E 52 (1995). [3] : Chao, A. W., & Mess, K. H. (Eds.). (2013). Handbook of accelerator physics and engineering. World scientific. 3rd Printing. p417. """ if dim == "y": pass elif dim == "x": sigmay, sigmax = sigmax, sigmay else: raise ValueError if ion == "CO": A = 28 elif ion == "H2": A = 2 sigma_i = ion_cross_section(ring, ion) d_gas = P / (Boltzmann*T) num = 4 * d_gas * sigma_i * beta * Nb**(3 / 2) * nb**2 * re * rp**( 1 / 2) * Lsep**(1 / 2) * c den = 3 * np.sqrt(3) * ring.gamma * sigmay**(3 / 2) * (sigmay + sigmax)**( 3 / 2) * A**(1 / 2) tau = den / num if model == "decoherence": tau = tau * 2 * np.sqrt(2) * nb * Lsep * delta_omega / c elif model == "non-linear": fi = ion_frequency(Nb, Lsep, sigmax, sigmay, ion, dim) tau = tau * 2 * pi * fi * ring.T1 * nb**(3 / 2) elif model == "linear": pass else: raise ValueError("model unknown") return tau
[docs]def plot_critical_mass(ring, bunch_charge, bunch_spacing, n_points=1e4): """ Plot ion critical mass, using Eq. (7.70) p147 of [1] Parameters ---------- ring : Synchrotron object bunch_charge : float Bunch charge in [C]. bunch_spacing : float Time in between two adjacent bunches in [s]. n_points : float or int, optional Number of point used in the plot. The default is 1e4. Returns ------- fig : figure References ---------- [1] : Gamelin, A. (2018). Collective effects in a transient microbunching regime and ion cloud mitigation in ThomX (Doctoral dissertation, Université Paris-Saclay). """ n_points = int(n_points) s = np.linspace(0, ring.L, n_points) sigma = ring.sigma(s) N = np.abs(bunch_charge / e) Ay = N * rp * bunch_spacing * c / (2 * sigma[2, :] * (sigma[2, :] + sigma[0, :])) Ax = N * rp * bunch_spacing * c / (2 * sigma[0, :] * (sigma[2, :] + sigma[0, :])) fig = plt.figure() ax = plt.gca() ax.plot(s, Ax, label=r"$A_x^c$") ax.plot(s, Ay, label=r"$A_y^c$") ax.set_yscale("log") ax.plot(s, np.ones_like(s) * 2, label=r"$H_2^+$") ax.plot(s, np.ones_like(s) * 16, label=r"$H_2O^+$") ax.plot(s, np.ones_like(s) * 18, label=r"$CH_4^+$") ax.plot(s, np.ones_like(s) * 28, label=r"$CO^+$") ax.plot(s, np.ones_like(s) * 44, label=r"$CO_2^+$") ax.legend() ax.set_ylabel("Critical mass") ax.set_xlabel("Longitudinal position [m]") return fig