From 5b0aa9382e7c404e58ad011152c9f8e95f443242 Mon Sep 17 00:00:00 2001 From: Watanyu Foosang <watanyu.f@gmail.com> Date: Fri, 26 Feb 2021 10:05:34 +0100 Subject: [PATCH] Add Courant-Snyder invariant calculation method to Bunch class --- tracking/element.py | 23 ++++++++++++++++++++++- tracking/monitors/__init__.py | 3 ++- tracking/monitors/monitors.py | 2 +- tracking/optics.py | 3 ++- tracking/particles.py | 10 ++++++++++ tracking/synchrotron.py | 15 +++++++++++++++ 6 files changed, 52 insertions(+), 4 deletions(-) diff --git a/tracking/element.py b/tracking/element.py index 0ef071c..00f75ed 100644 --- a/tracking/element.py +++ b/tracking/element.py @@ -125,7 +125,7 @@ class SynchrotronRadiation(Element): if (self.switch[0] == True): rand = np.random.normal(size=len(bunch)) bunch["delta"] = ((1 - 2*self.ring.T0/self.ring.tau[2])*bunch["delta"] + - 2*self.ring.sigma_delta*(self.ring.T0/self.ring.tau[2])**0.5*rand) + 2*self.ring.sigma_delta*(self.ring.T0/self.ring.tau[2])**0.5*rand) if (self.switch[1] == True): rand = np.random.normal(size=(len(bunch),2)) @@ -142,6 +142,27 @@ class SynchrotronRadiation(Element): # Reset energy change to 0 for next turn bunch.energy_change = 0 + #-------------------------------------- + # if (self.switch[0] == True): + # rand = np.random.normal(size=len(bunch)) + # bunch["delta"] = ((1 - 2*self.ring.T0/self.ring.tau[2])*bunch["delta"] + + # 2*self.ring.sigma_delta*(self.ring.T0/self.ring.tau[2])**0.5*rand) + + # if (self.switch[1] == True): + # rand = np.random.normal(size=(len(bunch),2)) + # bunch["x"] += self.ring.sigma[0]*(2*self.ring.T0/self.ring.tau[0])**0.5*rand[:,0] + # bunch["xp"] = (1 + bunch["delta"])/(1 + bunch["delta"] + bunch.energy_change)*bunch["xp"] + # bunch["xp"] += self.ring.sigma[1]*(2*self.ring.T0/self.ring.tau[0])**0.5*rand[:,1] + + # if (self.switch[2] == True): + # rand = np.random.normal(size=(len(bunch),2)) + # bunch["y"] += self.ring.sigma[2]*(2*self.ring.T0/self.ring.tau[1])**0.5*rand[:,0] + # bunch["yp"] = (1 + bunch["delta"])/(1 + bunch["delta"] + bunch.energy_change)*bunch["yp"] + # bunch["yp"] += self.ring.sigma[3]*(2*self.ring.T0/self.ring.tau[1])**0.5*rand[:,1] + + # # Reset energy change to 0 for next turn + # bunch.energy_change = 0 + #---------------------------------------- class TransverseMap(Element): """ Transverse map for a single turn in the synchrotron. diff --git a/tracking/monitors/__init__.py b/tracking/monitors/__init__.py index 1d186da..bd39dbd 100644 --- a/tracking/monitors/__init__.py +++ b/tracking/monitors/__init__.py @@ -15,4 +15,5 @@ from mbtrack2.tracking.monitors.plotting import (plot_bunchdata, plot_phasespacedata, plot_profiledata, plot_beamdata, - plot_wakedata) \ No newline at end of file + plot_wakedata, + plot_tunedata) \ No newline at end of file diff --git a/tracking/monitors/monitors.py b/tracking/monitors/monitors.py index 6a46e38..7a2b209 100644 --- a/tracking/monitors/monitors.py +++ b/tracking/monitors/monitors.py @@ -16,7 +16,7 @@ from mbtrack2.tracking.element import Element from mbtrack2.tracking.particles import Bunch, Beam from scipy.interpolate import interp1d from abc import ABCMeta -from mpi4py import MPI +#from mpi4py import MPI class Monitor(Element, metaclass=ABCMeta): """ diff --git a/tracking/optics.py b/tracking/optics.py index 58049c5..865a136 100644 --- a/tracking/optics.py +++ b/tracking/optics.py @@ -160,7 +160,7 @@ class Optics: kind='linear') self.disppY = interp1d(self.position, self.dispersion_array[3,:], kind='linear') - + @property def local_beta(self): """ @@ -215,6 +215,7 @@ class Optics: """ return self._local_gamma + def beta(self, position): """ Return beta functions at specific locations given by position. If no diff --git a/tracking/particles.py b/tracking/particles.py index 630e232..87988e8 100644 --- a/tracking/particles.py +++ b/tracking/particles.py @@ -231,6 +231,16 @@ class Bunch: np.mean(self['tau']*self['delta'])**2)**(0.5) return np.array([emitX, emitY, emitS]) + @property + def cs_invariant(self): + Jx = (self.ring.optics.local_gamma * np.mean(self['x']**2)) + \ + (2*self.ring.optics.local_alpha * np.mean(self['x']*self['xp'])) + \ + (self.ring.optics.local_beta * np.mean(self['xp']**2)) + Jy = (self.ring.optics.local_gamma * np.mean(self['y']**2)) + \ + (2*self.ring.optics.local_alpha * np.mean(self['y']*self['yp'])) + \ + (self.ring.optics.local_beta * np.mean(self['yp']**2)) + return np.array((Jx,Jy)) + @property def energy_change(self): """Store the particle relative energy change in the last turn. Used by diff --git a/tracking/synchrotron.py b/tracking/synchrotron.py index f5e2d69..1c45d8c 100644 --- a/tracking/synchrotron.py +++ b/tracking/synchrotron.py @@ -265,6 +265,21 @@ class Synchrotron: sigma[3,:] = (self.emit[1]*self.optics.alpha(position)[1] + self.optics.dispersion(position)[3]**2*self.sigma_delta)**0.5 return sigma + #------------------------------------------ + # @property + # def sigma(self): + # """RMS beam size at equilibrium""" + # sigma = np.zeros((4,)) + # sigma[0] = (self.emit[0]*self.optics.beta(10)[0] + + # self.optics.dispersion(10)[0]**2*self.sigma_delta)**0.5 + # sigma[1] = (self.emit[0]*self.optics.alpha(10)[0] + + # self.optics.dispersion(10)[1]**2*self.sigma_delta)**0.5 + # sigma[2] = (self.emit[1]*self.optics.beta(10)[1] + + # self.optics.dispersion(10)[2]**2*self.sigma_delta)**0.5 + # sigma[3] = (self.emit[1]*self.optics.alpha(10)[1] + + # self.optics.dispersion(10)[3]**2*self.sigma_delta)**0.5 + # return sigma + #------------------------------------------ def synchrotron_tune(self, Vrf): """ -- GitLab