diff --git a/mbtrack2/impedance/wakefield.py b/mbtrack2/impedance/wakefield.py
index 6f221f2f80a7cd66ec8ddb9476fdc11f480527ab..5ef7beada349bbcee1a8936354ebdc362632d324 100644
--- a/mbtrack2/impedance/wakefield.py
+++ b/mbtrack2/impedance/wakefield.py
@@ -600,6 +600,8 @@ class Impedance(ComplexData):
         Return a WakeFunction object from the impedance data.
     plot()
         Plot the impedance data.
+    to_pycolleff()
+        Convenience method to export impedance to pycolleff.
     """
 
     def __init__(self,
@@ -780,6 +782,34 @@ class Impedance(ComplexData):
         label = r"$Z_{" + self.component_type + r"}$" + unit
         ax.set_ylabel(label)
         return ax
+    
+    def to_pycolleff(self):
+        """
+        Convenience method to export impedance to pycolleff.
+        Only implemented for longitudinal impedance.
+
+        Returns
+        -------
+        imp : pycolleff.longitudinal_equilibrium.ImpedanceSource
+            pycolleff ImpedanceSource object
+        """
+        # pycolleff is a soft dependency
+        from pycolleff.longitudinal_equilibrium import ImpedanceSource
+        # avoid circular import
+        from mbtrack2.utilities.misc import double_sided_impedance
+        imp = ImpedanceSource()
+        if self.component_type == "long":
+            double_sided_impedance(self)
+            # Negative imag sign convention !
+            imp.zl_table = self.data["real"].to_numpy() - 1j*self.data["imag"].to_numpy()
+            imp.ang_freq_table = self.data.index.to_numpy() * 2 * np.pi
+        else:
+            raise NotImplementedError()
+        
+        imp.calc_method = ImpedanceSource.Methods.ImpedanceDFT
+        imp.active_passive = ImpedanceSource.ActivePassive.Passive
+        
+        return imp
 
 
 class WakeField:
diff --git a/mbtrack2/tracking/rf.py b/mbtrack2/tracking/rf.py
index a92c4b342c3c5a6e80d7b1cf9d99a573a388ed36..41284a1aa657f050bcd946d3aa79dc3b3d8a462d 100644
--- a/mbtrack2/tracking/rf.py
+++ b/mbtrack2/tracking/rf.py
@@ -7,7 +7,7 @@ import matplotlib.patches as mpatches
 import matplotlib.pyplot as plt
 import numpy as np
 from matplotlib.legend_handler import HandlerPatch
-
+from functools import partial
 from mbtrack2.instability import lcbi_growth_rate
 from mbtrack2.tracking.element import Element
 
@@ -191,6 +191,8 @@ class CavityResonator():
         Force feedback update from current CavityResonator parameters.
     sample_voltage()
         Sample the voltage seen by a zero charge particle during an RF period.
+    to_pycolleff()
+        Convenience method to export a CavityResonator to pycolleff.
     
     References
     ----------
@@ -1141,6 +1143,49 @@ class CavityResonator():
                           ref_frame="beam")
 
         return pos, voltage_rec
+    
+    def to_pycolleff(self, Impedance=True):
+        """
+        Convenience method to export a CavityResonator to pycolleff.
+        
+        Parameters
+        ----------
+        Impedance : bool, optional
+            If True, export as impedance (i.e. ImpedanceSource.Methods.ImpedanceDFT).
+            If False, export as wake (i.e. ImpedanceSource.Methods.Wake).
+            Default is True.
+
+        Returns
+        -------
+        cav : pycolleff ImpedanceSource object
+
+        """
+        # pycolleff is a soft dependency
+        from pycolleff.longitudinal_equilibrium import ImpedanceSource
+        
+        cav = ImpedanceSource()
+        cav.harm_rf = self.m
+        cav.Q = self.QL
+        RoverQ = self.RL/self.QL
+        cav.shunt_impedance = RoverQ * cav.Q
+        cav.ang_freq_rf = self.ring.omega1
+        cav.ang_freq = cav.harm_rf * cav.ang_freq_rf
+        cav.detune_w = 2 * np.pi * self.detune
+        if self.Vg != 0:
+            cav.active_passive = ImpedanceSource.ActivePassive.Active
+            if Impedance:
+                raise NotImplementedError()
+            else:
+                cav.calc_method = ImpedanceSource.Methods.Wake         
+        else:
+            cav.active_passive = ImpedanceSource.ActivePassive.Passive
+            if Impedance:
+                cav.calc_method = ImpedanceSource.Methods.ImpedanceDFT
+            else:
+                cav.calc_method = ImpedanceSource.Methods.Wake     
+        return cav
+        
+
 
 
 class ProportionalLoop():
diff --git a/mbtrack2/tracking/synchrotron.py b/mbtrack2/tracking/synchrotron.py
index b6e36fa2b06e579028a892c24aad1502ae961f88..fa37923a34e880e1c3ed3f8ceac3e28071dc5fc3 100644
--- a/mbtrack2/tracking/synchrotron.py
+++ b/mbtrack2/tracking/synchrotron.py
@@ -116,6 +116,8 @@ class Synchrotron:
         single or multi-harmonic RF systems.
     to_pyat(Vrf)
         Return a pyAT simple_ring element from the Synchrotron element data.
+    to_pycolleff(I0, Vrf, bunch_number)
+        Return a pycolleff Ring element from the Synchrotron element data.
     """
 
     def __init__(self, h, optics, particle, **kwargs):
@@ -584,3 +586,49 @@ class Synchrotron:
                                      U0=self.U0,
                                      TimeLag=TimeLag)
         return at_simple_ring
+    
+    def to_pycolleff(self, I0, Vrf, bunch_number):
+        """
+        Return a pycolleff Ring element from the Synchrotron element data.
+
+        Parameters
+        ----------
+        I0 : float
+            Beam current in [A].
+        Vrf : float
+            RF voltage in [V].
+        bunch_number : int
+            Total number of bunches filled.
+
+        Returns
+        -------
+        ring : pycolleff.colleff.Ring
+            pycolleff Ring object.
+
+        """
+        # pycolleff is a soft dependency
+        from pycolleff.colleff import Ring
+        
+        ring = Ring()
+        ring.version = 'from_mbtrack2'
+        ring.rf_freq = self.f1
+        ring.mom_comp = self.ac  # momentum compaction factor
+        ring.energy = self.E0  # energy [eV]
+        ring.tuney = self.tune[1]  # vertical tune
+        ring.tunex = self.tune[0]  # horizontal tune
+        ring.chromx = self.chro[0]  # horizontal chromaticity
+        ring.chromy = self.chro[1]  # vertical chromaticity
+        ring.harm_num = self.h  # harmonic Number
+        ring.num_bun = bunch_number  # number of bunches filled
+        ring.total_current = I0  # total current [A]
+        ring.sync_tune = self.synchrotron_tune(Vrf)  # synchrotron tune
+        ring.espread = self.sigma_delta
+        ring.bunlen = self.sigma_0*c  # [m]
+        ring.damptx = self.tau[0]  # [s]
+        ring.dampty = self.tau[1]  # [s]
+        ring.dampte = self.tau[2]  # [s]
+        ring.en_lost_rad = self.U0 # [eV]
+        ring.gap_voltage = Vrf  # [V]
+        
+        return ring
+
diff --git a/mbtrack2/utilities/beamloading.py b/mbtrack2/utilities/beamloading.py
index 19e51e98749451baad6eb72e195f1a44d9995d4b..b51554f48d137699de1a86de397eefbe9f5bd3d8 100644
--- a/mbtrack2/utilities/beamloading.py
+++ b/mbtrack2/utilities/beamloading.py
@@ -6,18 +6,14 @@ Module where the BeamLoadingEquilibrium class is defined.
 import matplotlib.pyplot as plt
 import numpy as np
 from scipy.constants import c
-from scipy.integrate import quad
+from scipy.integrate import trapz
 from scipy.optimize import root
-
+from mbtrack2.utilities.spectrum import gaussian_bunch
 
 class BeamLoadingEquilibrium():
     """Class used to compute beam equilibrium profile for a given storage ring 
     and a list of RF cavities of any harmonic. The class assumes an uniform 
-    filling of the storage ring. Based on an extension of [1].
-
-    [1] Venturini, M. (2018). Passive higher-harmonic rf cavities with general
-    settings and multibunch instabilities in electron storage rings.
-    Physical Review Accelerators and Beams, 21(11), 114404.
+    filling of the storage ring. Based on [1] which is an extension of [2].
 
     Parameters
     ----------
@@ -30,8 +26,20 @@ class BeamLoadingEquilibrium():
     PHI : list of form factor phase
     B1 : lower intergration boundary
     B2 : upper intergration boundary
+    N : int or float, optinal
+        Number of points used for longitudinal grid.
+        Default is 1000.
+    
+    References
+    ----------
+    [1] Gamelin, A., & Yamamoto, N. (2021). Equilibrium bunch density 
+    distribution with multiple active and passive RF cavities. 
+    IPAC'21 (MOPAB069).
+    [2] Venturini, M. (2018). Passive higher-harmonic rf cavities with general
+    settings and multibunch instabilities in electron storage rings.
+    Physical Review Accelerators and Beams, 21(11), 114404.
+    
     """
-
     def __init__(self,
                  ring,
                  cavity_list,
@@ -40,7 +48,8 @@ class BeamLoadingEquilibrium():
                  F=None,
                  PHI=None,
                  B1=-0.2,
-                 B2=0.2):
+                 B2=0.2,
+                 N=1000):
         self.ring = ring
         self.cavity_list = cavity_list
         self.I0 = I0
@@ -57,7 +66,10 @@ class BeamLoadingEquilibrium():
         self.B1 = B1
         self.B2 = B2
         self.mpi = False
-        self.__version__ = "1.0"
+        self.N = N
+        self.z0 = np.linspace(self.B1, self.B2, self.N)
+        self.tau0 = self.z0/c
+        self.rho0 = gaussian_bunch(self.tau0, self.ring.sigma_0)/c
 
         # Define constants for scaled potential u(z)
         self.u0 = self.ring.U0 / (self.ring.ac * self.ring.sigma_delta**2 *
@@ -65,6 +77,11 @@ class BeamLoadingEquilibrium():
         self.ug = np.zeros((self.n_cavity, ))
         self.ub = np.zeros((self.n_cavity, ))
         self.update_potentials()
+                  
+    def update_rho(self):
+        uexp_vals = self.uexp(self.z0)
+        A = trapz(uexp_vals, x=self.z0)
+        self.rho0 = uexp_vals / A
 
     def update_potentials(self):
         """Update potentials with cavity and ring data."""
@@ -90,9 +107,7 @@ class BeamLoadingEquilibrium():
 
     def center_of_mass(self):
         """Return center of mass position in [s]"""
-        z0 = np.linspace(self.B1, self.B2, 1000)
-        rho = self.rho(z0)
-        CM = np.average(z0, weights=rho)
+        CM = np.average(self.z0, weights=self.rho0)
         return CM / c
 
     def u(self, z):
@@ -122,12 +137,12 @@ class BeamLoadingEquilibrium():
 
     def uexp(self, z):
         return np.exp(-1 * self.u(z))
-
+  
     def integrate_func(self, f, g):
         """Return Integral[f*g]/Integral[f] between B1 and B2"""
-        A = quad(lambda x: f(x) * g(x), self.B1, self.B2)
-        B = quad(f, self.B1, self.B2)
-        return A[0] / B[0]
+        A = trapz(f*g, x=self.z0)
+        B = trapz(f, x=self.z0)
+        return A / B
 
     def to_solve(self, x, CM=True):
         """System of non-linear equation to solve to find the form factors F
@@ -150,6 +165,7 @@ class BeamLoadingEquilibrium():
         else:
             self.F = x[::2]
         self.PHI = x[1::2]
+        self.update_rho()
 
         # Compute system
         if self.auto_set_MC_theta:
@@ -158,12 +174,12 @@ class BeamLoadingEquilibrium():
                 cavity = self.cavity_list[i]
                 res[2 *
                     i] = self.F[i] * np.cos(self.PHI[i]) - self.integrate_func(
-                        lambda y: self.uexp(y),
-                        lambda y: np.cos(self.ring.k1 * cavity.m * y))
+                        self.uexp(self.z0),
+                        np.cos(self.ring.k1 * cavity.m * self.z0))
                 res[2*i +
                     1] = self.F[i] * np.sin(self.PHI[i]) - self.integrate_func(
-                        lambda y: self.uexp(y),
-                        lambda y: np.sin(self.ring.k1 * cavity.m * y))
+                        self.uexp(self.z0),
+                        np.sin(self.ring.k1 * cavity.m * self.z0))
             # Factor 1e-8 or 1e12 for better convergence
             if CM is True:
                 res[self.n_cavity * 2] = self.center_of_mass() * 1e12
@@ -175,27 +191,17 @@ class BeamLoadingEquilibrium():
                 cavity = self.cavity_list[i]
                 res[2 *
                     i] = self.F[i] * np.cos(self.PHI[i]) - self.integrate_func(
-                        lambda y: self.uexp(y),
-                        lambda y: np.cos(self.ring.k1 * cavity.m * y))
+                        self.uexp(self.z0),
+                        np.cos(self.ring.k1 * cavity.m * self.z0))
                 res[2*i +
                     1] = self.F[i] * np.sin(self.PHI[i]) - self.integrate_func(
-                        lambda y: self.uexp(y),
-                        lambda y: np.sin(self.ring.k1 * cavity.m * y))
+                        self.uexp(self.z0),
+                        np.sin(self.ring.k1 * cavity.m * self.z0))
         return res
 
-    def rho(self, z):
-        """Return bunch equilibrium profile at postion z"""
-        A = quad(lambda y: self.uexp(y), self.B1, self.B2)
-        return self.uexp(z) / A[0]
-
-    def plot_rho(self, z1=None, z2=None):
-        """Plot the bunch equilibrium profile between z1 and z2"""
-        if z1 is None:
-            z1 = self.B1
-        if z2 is None:
-            z2 = self.B2
-        z0 = np.linspace(z1, z2, 1000)
-        plt.plot(z0 / c * 1e12, self.rho(z0))
+    def plot_rho(self):
+        """Plot the bunch equilibrium profile"""
+        plt.plot(self.tau0 * 1e12, self.rho0)
         plt.xlabel(r"$\tau$ [ps]")
         plt.title("Equilibrium bunch profile")
 
@@ -231,38 +237,22 @@ class BeamLoadingEquilibrium():
             Vtot += cavity.deltaVRF(z, self.I0, self.F[i], self.PHI[i])
         return Vtot
 
-    def plot_dV(self, z1=None, z2=None):
-        """Plot the derivative of RF system total voltage between z1 and z2"""
-        if z1 is None:
-            z1 = self.B1
-        if z2 is None:
-            z2 = self.B2
-        z0 = np.linspace(z1, z2, 1000)
-        plt.plot(z0, self.dV(z0))
+    def plot_dV(self):
+        """Plot the derivative of RF system total voltage"""
+        plt.plot(self.z0, self.dV(self.z0))
         plt.xlabel("z [m]")
         plt.ylabel("Total RF voltage (V)")
 
-    def plot_voltage(self, z1=None, z2=None):
+    def plot_voltage(self):
         """Plot the RF system total voltage between z1 and z2"""
-        if z1 is None:
-            z1 = self.B1
-        if z2 is None:
-            z2 = self.B2
-        z0 = np.linspace(z1, z2, 1000)
-        plt.plot(z0, self.voltage(z0))
+        plt.plot(self.z0, self.voltage(self.z0))
         plt.xlabel("z [m]")
         plt.ylabel("Total RF voltage (V)")
 
-    def std_rho(self, z1=None, z2=None):
+    def std_rho(self):
         """Return the rms bunch equilibrium size in [m]"""
-        if z1 is None:
-            z1 = self.B1
-        if z2 is None:
-            z2 = self.B2
-        z0 = np.linspace(z1, z2, 1000)
-        values = self.rho(z0)
-        average = np.average(z0, weights=values)
-        variance = np.average((z0 - average)**2, weights=values)
+        average = np.average(self.z0, weights=self.rho0)
+        variance = np.average((self.z0 - average)**2, weights=self.rho0)
         return np.sqrt(variance)
 
     def beam_equilibrium(self,
@@ -333,7 +323,7 @@ class BeamLoadingEquilibrium():
                 print("The algorithm has converged: " + str(sol.success))
 
         if plot:
-            self.plot_rho(self.B1 / 4, self.B2 / 4)
+            self.plot_rho()
 
         return sol
 
@@ -404,3 +394,19 @@ class BeamLoadingEquilibrium():
                 (2 * np.pi * HC.m**2 * self.F[1] * self.ring.h * I0 * f))
 
         return (eta, RQth, f)
+    
+    @property
+    def R_factor(self):
+        """
+        Touschek lifetime ratio as defined in [1].
+            
+        Reference
+        ---------
+        [1] : Byrd, J. M., and M. Georgsson. "Lifetime increase using passive 
+        harmonic cavities in synchrotron light sources." Physical Review 
+        Special Topics-Accelerators and Beams 4.3 (2001): 030701.
+
+        """
+        rho0 = gaussian_bunch(self.tau0, self.ring.sigma_0)/c
+        R = trapz(rho0**2, self.tau0)/trapz(self.rho0**2, self.tau0)
+        return R