Select Git revision
-
BRONES Romain authored
* this avoid lauchning the comlbp, and let the LBP outside of the com * also tag version
BRONES Romain authored* this avoid lauchning the comlbp, and let the LBP outside of the com * also tag version
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
synchrotron.py 8.46 KiB
# -*- coding: utf-8 -*-
"""
Module where the synchrotron class is defined.
@author: Alexis Gamelin
@date: 15/01/2020
"""
import numpy as np
from scipy.constants import c, e
class Synchrotron:
"""
Synchrotron class to store main properties.
Optional parameters are optional only if the Optics object passed to the
class uses a loaded lattice.
Parameters
----------
h : int
Harmonic number of the accelerator.
optics : Optics object
Object where the optic functions are stored.
particle : Particle object
Particle which is accelerated.
tau : array of shape (3,)
Horizontal, vertical and longitudinal damping times in [s].
sigma_delta : float
Equilibrium energy spread.
sigma_0 : float
Natural bunch length in [s].
emit : array of shape (2,)
Horizontal and vertical equilibrium emittance in [m.rad].
L : float, optional
Ring circumference in [m].
E0 : float, optional
Nominal (total) energy of the ring in [eV].
ac : float, optional
Momentum compaction factor.
tune : array of shape (2,), optional
Horizontal and vertical tunes.
chro : array of shape (2,), optional
Horizontal and vertical (non-normalized) chromaticities.
U0 : float, optional
Energy loss per turn in [eV].
Attributes
----------
T0 : float
Revolution time in [s].
f0 : float
Revolution frequency in [Hz].
omega0 : float
Angular revolution frequency in [Hz.rad]
T1 : flaot
Fundamental RF period in [s].
f1 : float
Fundamental RF frequency in [Hz].
omega1 : float
Fundamental RF angular frequency in [Hz.rad].
k1 : float
Fundamental RF wave number in [m**-1].
gamma : float
Relativistic Lorentz gamma.
beta : float
Relativistic Lorentz beta.
eta : float
Momentum compaction.
sigma : array of shape (4,)
RMS beam size at equilibrium in [m].
Methods
-------
synchrotron_tune(Vrf)
Compute synchrotron tune from RF voltage.
"""
def __init__(self, h, optics, particle, **kwargs):
self._h = h
self.particle = particle
self.optics = optics
if self.optics.use_local_values == False:
self.L = kwargs.get('L', self.optics.lattice.circumference)
self.E0 = kwargs.get('E0', self.optics.lattice.energy)
self.ac = kwargs.get('ac', self.optics.ac)
self.tune = kwargs.get('tune', self.optics.tune)
self.chro = kwargs.get('chro', self.optics.chro)
self.U0 = kwargs.get('U0', self.optics.lattice.energy_loss)
else:
self.L = kwargs.get('L') # Ring circumference [m]
self.E0 = kwargs.get('E0') # Nominal (total) energy of the ring [eV]
self.ac = kwargs.get('ac') # Momentum compaction factor
self.tune = kwargs.get('tune') # X/Y/S tunes
self.chro = kwargs.get('chro') # X/Y (non-normalized) chromaticities
self.U0 = kwargs.get('U0') # Energy loss per turn [eV]
self.tau = kwargs.get('tau') # X/Y/S damping times [s]
self.sigma_delta = kwargs.get('sigma_delta') # Equilibrium energy spread
self.sigma_0 = kwargs.get('sigma_0') # Natural bunch length [s]
self.emit = kwargs.get('emit') # X/Y emittances in [m.rad]
@property
def h(self):
"""Harmonic number"""
return self._h
@h.setter
def h(self, value):
self._h = value
self.L = self.L # call setter
@property
def L(self):
"""Ring circumference [m]"""
return self._L
@L.setter
def L(self,value):
self._L = value
self._T0 = self.L/c
self._T1 = self.T0/self.h
self._f0 = 1/self.T0
self._omega0 = 2*np.pi*self.f0
self._f1 = self.h*self.f0
self._omega1 = 2*np.pi*self.f1
self._k1 = self.omega1/c
@property
def T0(self):
"""Revolution time [s]"""
return self._T0
@T0.setter
def T0(self, value):
self.L = c*value
@property
def T1(self):
""""Fundamental RF period [s]"""
return self._T1
@T1.setter
def T1(self, value):
self.L = c*value*self.h
@property
def f0(self):
"""Revolution frequency [Hz]"""
return self._f0
@f0.setter
def f0(self,value):
self.L = c/value
@property
def omega0(self):
"""Angular revolution frequency [Hz rad]"""
return self._omega0
@omega0.setter
def omega0(self,value):
self.L = 2*np.pi*c/value
@property
def f1(self):
"""Fundamental RF frequency [Hz]"""
return self._f1
@f1.setter
def f1(self,value):
self.L = self.h*c/value
@property
def omega1(self):
"""Fundamental RF angular frequency[Hz rad]"""
return self._omega1
@omega1.setter
def omega1(self,value):
self.L = 2*np.pi*self.h*c/value
@property
def k1(self):
"""Fundamental RF wave number [m**-1]"""
return self._k1
@k1.setter
def k1(self,value):
self.L = 2*np.pi*self.h/value
@property
def gamma(self):
"""Relativistic gamma"""
return self._gamma
@gamma.setter
def gamma(self, value):
self._gamma = value
self._beta = np.sqrt(1 - self.gamma**-2)
self._E0 = self.gamma*self.particle.mass*c**2/e
@property
def beta(self):
"""Relativistic beta"""
return self._beta
@beta.setter
def beta(self, value):
self.gamma = 1/np.sqrt(1-value**2)
@property
def E0(self):
"""Nominal (total) energy of the ring [eV]"""
return self._E0
@E0.setter
def E0(self, value):
self.gamma = value/(self.particle.mass*c**2/e)
@property
def eta(self):
"""Momentum compaction"""
return self.ac - 1/(self.gamma**2)
def sigma(self, position=None):
"""
RMS beam size at equilibrium
Parameters
----------
position : float or array, optional
Longitudinal position where the beam size is computed. If None,
the local values are used.
Returns
-------
sigma : array
RMS beam size at position location or at local positon if position
is None.
"""
if position is None:
sigma = np.zeros((4,))
sigma[0] = (self.emit[0]*self.optics.local_beta[0] +
self.optics.local_dispersion[0]**2*self.sigma_delta)**0.5
sigma[1] = (self.emit[0]*self.optics.local_alpha[0] +
self.optics.local_dispersion[1]**2*self.sigma_delta)**0.5
sigma[2] = (self.emit[1]*self.optics.local_beta[1] +
self.optics.local_dispersion[2]**2*self.sigma_delta)**0.5
sigma[3] = (self.emit[1]*self.optics.local_alpha[1] +
self.optics.local_dispersion[3]**2*self.sigma_delta)**0.5
else:
if isinstance(position, (float, int)):
n = 1
else:
n = len(position)
sigma = np.zeros((4, n))
sigma[0,:] = (self.emit[0]*self.optics.beta(position)[0] +
self.optics.dispersion(position)[0]**2*self.sigma_delta)**0.5
sigma[1,:] = (self.emit[0]*self.optics.alpha(position)[0] +
self.optics.dispersion(position)[1]**2*self.sigma_delta)**0.5
sigma[2,:] = (self.emit[1]*self.optics.beta(position)[1] +
self.optics.dispersion(position)[2]**2*self.sigma_delta)**0.5
sigma[3,:] = (self.emit[1]*self.optics.alpha(position)[1] +
self.optics.dispersion(position)[3]**2*self.sigma_delta)**0.5
return sigma
def synchrotron_tune(self, Vrf):
"""
Compute synchrotron tune from RF voltage
Parameters
----------
Vrf : float
Main RF voltage in [V].
Returns
-------
tuneS : float
Synchrotron tune.
"""
phase = np.pi - np.arcsin(self.U0 / Vrf)
tuneS = np.sqrt( - (Vrf / self.E0) * (self.h * self.ac) / (2*np.pi)
* np.cos(phase) )
return tuneS