diff --git a/collective_effects/__init__.py b/collective_effects/__init__.py
index e726ab119ddd11697b0a30f769798d1662090f9b..2740b8b659e6c45aa896ef7f76fed9551c8757ed 100644
--- a/collective_effects/__init__.py
+++ b/collective_effects/__init__.py
@@ -5,7 +5,7 @@ Created on Tue Jan 14 12:25:30 2020
 @author: gamelina
 """
 
-from mbtrack2.collective_effects.instabilities import mbi_threshold, cbi_threshold, lcbi_growth_rate_mode, lcbi_growth_rate, plot_critical_mass
+from mbtrack2.collective_effects.instabilities import mbi_threshold, cbi_threshold, lcbi_growth_rate_mode, lcbi_growth_rate
 from mbtrack2.collective_effects.resistive_wall import (skin_depth, CircularResistiveWall, Coating)
 from mbtrack2.collective_effects.resonator import Resonator, PureInductive, PureResistive
 from mbtrack2.collective_effects.tapers import StupakovRectangularTaper, StupakovCircularTaper
@@ -16,4 +16,5 @@ from mbtrack2.collective_effects.utilities import yokoya_elliptic, beam_loss_fac
 from mbtrack2.collective_effects.utilities import double_sided_impedance, read_IW2D_folder
 from mbtrack2.collective_effects.utilities import gaussian_bunch
 from mbtrack2.collective_effects.impedance_model import ImpedanceModel
-from mbtrack2.collective_effects.csr import (FreeSpaceCSR, ParallelPlatesCSR)
\ No newline at end of file
+from mbtrack2.collective_effects.csr import (FreeSpaceCSR, ParallelPlatesCSR)
+from mbtrack2.collective_effects.ions import ion_cross_section, ion_frequency, fast_beam_ion, plot_critical_mass
\ No newline at end of file
diff --git a/collective_effects/ions.py b/collective_effects/ions.py
new file mode 100644
index 0000000000000000000000000000000000000000..66be6a06934ee2afa6f0fa3624b0215c17eae0d4
--- /dev/null
+++ b/collective_effects/ions.py
@@ -0,0 +1,255 @@
+# -*- coding: utf-8 -*-
+"""
+Various calculations about ion trapping and instabilities in electron storage 
+rings.
+
+@author: Alexis Gamelin
+"""
+
+import numpy as np
+import matplotlib.pyplot as plt
+from scipy.constants import c, m_e, e, pi, epsilon_0, hbar, Boltzmann, physical_constants, m_p
+
+rp = 1/(4*pi*epsilon_0) * e**2 / (m_p * c**2)
+re = physical_constants["classical electron radius"][0]
+
+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
+
+def ion_frequency(N, Lesp, sigmax, sigmay, ion="CO", dim="y", express="coupling"):
+    """
+    Compute the ion oscillation frequnecy.
+
+    Parameters
+    ----------
+    N : float
+        Number of electrons per bunch.
+    Lesp : 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 * Lesp * sigmay * (sigmax + sigmay) ) ) / (2*pi)
+    
+    return f
+    
+def fast_beam_ion(ring, Nb, nb, Lsep, sigmax, sigmay, P, T, beta, 
+                  decoherence=True, delta_omega = 0, ion="CO", dim="y"):
+    """
+    Compute fast beam ion instability rise time [1].
+    
+    Warning ! If decoherence=False, the rise time is not an e-folding time 
+    (i.e. y ~ exp(t/tau)) but an assymptotic grow time 
+    (i.e. y ~ exp(sqrt(t/tau))) see [1][2].
+    
+    The decoherence model assumes that [2]:
+        Lsep << c / (2 * pi * ion_frequency) 
+        Lsep << c / (2 * pi * betatron_frequency) 
+
+    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].
+    decoherence : bool, optional
+        If True, decoherence is taken into account using [2].
+    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).
+    
+    """
+    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 decoherence is True:
+        tau = tau * 2 * np.sqrt(2) * nb * Lsep * delta_omega / c
+    
+    return tau 
+
+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
+    
\ No newline at end of file