Skip to content

Commit 4325cd4

Browse files
committed
Merge pull request #2 from PyCOMPLETE/develop
v1.3.2 (compatibility with PyHEADTAIL v1.3.2)
2 parents 9d836cb + 4de82f6 commit 4325cd4

File tree

2 files changed

+252
-25
lines changed

2 files changed

+252
-25
lines changed

CERNmachines.py

Lines changed: 220 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,134 @@
33
import numpy as np
44
from scipy.constants import c, e, m_p
55

6-
from machines import synchrotron
6+
from machines import Synchrotron
77

88

9-
class SPS(synchrotron):
9+
class PSB(Synchrotron):
10+
11+
def __init__(self, *args, **kwargs):
12+
13+
if 'n_segments' not in kwargs.keys():
14+
raise ValueError('Number of segments must be specified')
15+
16+
if 'machine_configuration' not in kwargs.keys():
17+
raise ValueError('machine_configuration must be specified')
18+
19+
self.n_segments = kwargs['n_segments']
20+
self.machine_configuration = kwargs['machine_configuration']
21+
22+
self.circumference = 50*np.pi
23+
self.s = (np.arange(0, self.n_segments + 1)
24+
* self.circumference / self.n_segments)
25+
26+
if self.machine_configuration == '160MeV':
27+
self.charge = e
28+
self.mass = m_p
29+
30+
self.gamma = 160e6*e/(self.mass*c**2) + 1
31+
32+
self.Q_x = 4.23
33+
self.Q_y = 4.37
34+
35+
self.Qp_x = -1*self.Q_x
36+
self.Qp_y = -2*self.Q_y
37+
38+
self.app_x = 0.0000e-9
39+
self.app_y = 0.0000e-9
40+
self.app_xy = 0
41+
42+
self.alpha_x = 0 * np.ones(self.n_segments)
43+
self.beta_x = self.circumference/(2*np.pi*self.Q_x) * np.ones(self.n_segments)
44+
self.D_x = 0 * np.ones(self.n_segments)
45+
self.alpha_y = 0 * np.ones(self.n_segments)
46+
self.beta_y = self.circumference/(2*np.pi*self.Q_y) * np.ones(self.n_segments)
47+
self.D_y = 0 * np.ones(self.n_segments)
48+
49+
self.alpha = 0.06
50+
self.h1 = 1
51+
self.h2 = 2
52+
self.V1 = 8e3
53+
self.V2 = 0
54+
self.dphi1 = 0
55+
self.dphi2 = np.pi
56+
self.p_increment = 0 * e/c * self.circumference/(self.beta*c)
57+
58+
self.longitudinal_focusing = 'non-linear'
59+
60+
elif self.machine_configuration == '1GeV':
61+
self.charge = e
62+
self.mass = m_p
63+
64+
self.gamma = 1e9*e/(self.mass*c**2) + 1
65+
66+
self.Q_x = 4.23
67+
self.Q_y = 4.37
68+
69+
self.Qp_x = -1*self.Q_x
70+
self.Qp_y = -2*self.Q_y
71+
72+
self.app_x = 0.0000e-9
73+
self.app_y = 0.0000e-9
74+
self.app_xy = 0
75+
76+
self.alpha_x = 0 * np.ones(self.n_segments)
77+
self.beta_x = self.circumference/(2*np.pi*self.Q_x) * np.ones(self.n_segments)
78+
self.D_x = 0 * np.ones(self.n_segments)
79+
self.alpha_y = 0 * np.ones(self.n_segments)
80+
self.beta_y = self.circumference/(2*np.pi*self.Q_y) * np.ones(self.n_segments)
81+
self.D_y = 0 * np.ones(self.n_segments)
82+
83+
self.alpha = 0.06
84+
self.h1 = 1
85+
self.h2 = 2
86+
self.V1 = 8e3
87+
self.V2 = 0
88+
self.dphi1 = 0
89+
self.dphi2 = np.pi
90+
self.p_increment = 0 * e/c * self.circumference/(self.beta*c)
91+
92+
self.longitudinal_focusing = 'non-linear'
93+
94+
elif self.machine_configuration == '1.4GeV':
95+
self.charge = e
96+
self.mass = m_p
97+
98+
self.gamma = 1.4e9*e/(self.mass*c**2) + 1
99+
100+
self.Q_x = 4.23
101+
self.Q_y = 4.37
102+
103+
self.Qp_x = -1*self.Q_x
104+
self.Qp_y = -2*self.Q_y
105+
106+
self.app_x = 0.0000e-9
107+
self.app_y = 0.0000e-9
108+
self.app_xy = 0
109+
110+
self.alpha_x = 0 * np.ones(self.n_segments)
111+
self.beta_x = self.circumference/(2*np.pi*self.Q_x) * np.ones(self.n_segments)
112+
self.D_x = 0 * np.ones(self.n_segments)
113+
self.alpha_y = 0 * np.ones(self.n_segments)
114+
self.beta_y = self.circumference/(2*np.pi*self.Q_y) * np.ones(self.n_segments)
115+
self.D_y = 0 * np.ones(self.n_segments)
116+
117+
self.alpha = 0.06
118+
self.h1 = 1
119+
self.h2 = 2
120+
self.V1 = 8e3
121+
self.V2 = 0
122+
self.dphi1 = 0
123+
self.dphi2 = np.pi
124+
self.p_increment = 0 * e/c * self.circumference/(self.beta*c)
125+
126+
self.longitudinal_focusing = 'non-linear'
127+
else:
128+
raise ValueError('Unknown configuration '+self.machine_configuration)
129+
130+
super(PSB, self).__init__(*args, **kwargs)
131+
132+
133+
class SPS(Synchrotron):
10134

11135
def __init__(self, *args, **kwargs):
12136

@@ -122,7 +246,7 @@ def __init__(self, *args, **kwargs):
122246
super(SPS, self).__init__(*args, **kwargs)
123247

124248

125-
class HLLHC(synchrotron):
249+
class LHC(Synchrotron):
126250

127251
def __init__(self, *args, **kwargs):
128252

@@ -139,30 +263,118 @@ def __init__(self, *args, **kwargs):
139263
self.s = (np.arange(0, self.n_segments + 1)
140264
* self.circumference / self.n_segments)
141265

142-
if self.machine_configuration == '7TeV':
266+
if self.machine_configuration == '450GeV':
267+
self.charge = e
268+
self.mass = m_p
269+
270+
self.gamma = np.sqrt( (450e9*e/(self.mass*c**2))**2 + 1 )
271+
272+
self.Q_x = 64.28
273+
self.Q_y = 59.31
274+
275+
self.alpha_x = 0 * np.ones(self.n_segments)
276+
self.beta_x = self.R/self.Q_x * np.ones(self.n_segments)
277+
self.D_x = 0 * np.ones(self.n_segments)
278+
self.alpha_y = 0 * np.ones(self.n_segments)
279+
self.beta_y = self.R/self.Q_y * np.ones(self.n_segments)
280+
self.D_y = 0 * np.ones(self.n_segments)
281+
282+
self.Qp_x = 0
283+
self.Qp_y = 0
284+
285+
self.app_x = 0.0000e-9
286+
self.app_y = 0.0000e-9
287+
self.app_xy = 0
288+
289+
self.alpha = 3.225e-4
290+
self.h1 = 35640
291+
self.h2 = 71280
292+
self.V1 = 8e6
293+
self.V2 = 0
294+
self.dphi1 = 0
295+
self.dphi2 = np.pi
296+
self.p_increment = 0 * e/c * self.circumference/(self.beta*c)
297+
298+
self.longitudinal_focusing = 'non-linear'
299+
300+
elif self.machine_configuration == '7TeV':
143301
self.charge = e
144302
self.mass = m_p
145303

146304
self.gamma = np.sqrt( (7000e9*e/(self.mass*c**2))**2 + 1 )
147305

306+
self.Q_x = 64.31
307+
self.Q_y = 59.32
308+
148309
self.alpha_x = 0 * np.ones(self.n_segments)
149-
self.beta_x = 65.9756337546 * np.ones(self.n_segments)
310+
self.beta_x = self.R/self.Q_x * np.ones(self.n_segments)
150311
self.D_x = 0 * np.ones(self.n_segments)
151312
self.alpha_y = 0 * np.ones(self.n_segments)
152-
self.beta_y = 71.5255058456 * np.ones(self.n_segments)
313+
self.beta_y = self.R/self.Q_y * np.ones(self.n_segments)
153314
self.D_y = 0 * np.ones(self.n_segments)
154315

155-
self.Q_x = 60.31
316+
self.Qp_x = 0
317+
self.Qp_y = 0
318+
319+
self.app_x = 0.0000e-9
320+
self.app_y = 0.0000e-9
321+
self.app_xy = 0
322+
323+
self.alpha = 3.225e-4
324+
self.h1 = 35640
325+
self.h2 = 71280
326+
self.V1 = 16e6
327+
self.V2 = 0
328+
self.dphi1 = 0
329+
self.dphi2 = np.pi
330+
self.p_increment = 0 * e/c * self.circumference/(self.beta*c)
331+
332+
self.longitudinal_focusing = 'non-linear'
333+
334+
super(LHC, self).__init__(*args, **kwargs)
335+
336+
337+
class HLLHC(Synchrotron):
338+
339+
def __init__(self, *args, **kwargs):
340+
341+
if 'n_segments' not in kwargs.keys():
342+
raise ValueError('Number of segments must be specified')
343+
344+
if 'machine_configuration' not in kwargs.keys():
345+
raise ValueError('machine_configuration must be specified')
346+
347+
self.n_segments = kwargs['n_segments']
348+
self.machine_configuration = kwargs['machine_configuration']
349+
350+
self.circumference = 26658.883
351+
self.s = (np.arange(0, self.n_segments + 1)
352+
* self.circumference / self.n_segments)
353+
354+
if self.machine_configuration == '7TeV':
355+
self.charge = e
356+
self.mass = m_p
357+
358+
self.gamma = np.sqrt( (7000e9*e/(self.mass*c**2))**2 + 1 )
359+
360+
self.Q_x = 62.31
156361
self.Q_y = 60.32
157362

363+
self.alpha_x = 0 * np.ones(self.n_segments)
364+
self.beta_x = self.R/self.Q_x * np.ones(self.n_segments)
365+
self.D_x = 0 * np.ones(self.n_segments)
366+
self.alpha_y = 0 * np.ones(self.n_segments)
367+
self.beta_y = self.R/self.Q_y * np.ones(self.n_segments)
368+
self.D_y = 0 * np.ones(self.n_segments)
369+
158370
self.Qp_x = 0
159371
self.Qp_y = 0
160372

161373
self.app_x = 0.0000e-9
162374
self.app_y = 0.0000e-9
163375
self.app_xy = 0
164376

165-
self.alpha = 0.0003225
377+
self.alpha = 53.83**-2
166378
self.h1 = 35640
167379
self.h2 = 71280
168380
self.V1 = 16e6

machines.py

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
from PyHEADTAIL.trackers.simple_long_tracking import LinearMap, RFSystems
1111

1212

13-
class synchrotron(Element):
13+
class Synchrotron(Element):
1414

1515
def __init__(self, *args, **kwargs):
1616

@@ -77,6 +77,14 @@ def Q_s(self):
7777
return np.sqrt( e*np.abs(self.eta)*(self.h1*self.V1 + self.h2*self.V2)
7878
/ (2*np.pi*self.p0*self.beta*c) )
7979

80+
@property
81+
def beta_z(self):
82+
return np.abs(self.eta)*self.circumference/2./np.pi/self.Q_s
83+
84+
@property
85+
def R(self):
86+
return self.circumference/(2*np.pi)
87+
8088
def track(self, bunch, verbose = False):
8189
for m in self.one_turn_map:
8290
if verbose:
@@ -85,11 +93,8 @@ def track(self, bunch, verbose = False):
8593
m.track(bunch)
8694

8795
def create_transverse_map(self):
88-
try:
89-
chromaticity = Chromaticity(self.Qp_x, self.Qp_y)
90-
except TypeError as error:
91-
chromaticity = Chromaticity([self.Qp_x], [self.Qp_y])
92-
self.warns('Converted to new interface - takes chromaticities as lists.')
96+
97+
chromaticity = Chromaticity(self.Qp_x, self.Qp_y)
9398
amplitude_detuning = AmplitudeDetuning(self.app_x, self.app_y, self.app_xy)
9499

95100
self.transverse_map = TransverseMap(
@@ -102,17 +107,19 @@ def create_transverse_map(self):
102107
def create_longitudinal_map(self):
103108

104109
if self.longitudinal_focusing == 'linear':
105-
self.longitudinal_map = LinearMap([self.alpha], self.circumference, self.Q_s)
110+
self.longitudinal_map = LinearMap([self.alpha], self.circumference,
111+
self.Q_s, D_x=self.D_x[0], D_y=self.D_y[0])
106112
elif self.longitudinal_focusing == 'non-linear':
107113
self.longitudinal_map = RFSystems(self.circumference, [self.h1, self.h2], [self.V1, self.V2], [self.dphi1, self.dphi2],
108-
[self.alpha], self.gamma, self.p_increment)
114+
[self.alpha], self.gamma, self.p_increment,
115+
D_x=self.D_x[0], D_y=self.D_y[0])
109116
else:
110117
raise ValueError('ERROR: unknown focusing', self.longitudinal_focusing)
111118

112119
def generate_6D_Gaussian_bunch(self, n_macroparticles, intensity, epsn_x, epsn_y, sigma_z):
113120
'''
114121
Generates a 6D Gaussian distribution of particles which is transversely
115-
matched to the synchrotron. Longitudinally, the distribution is matched
122+
matched to the Synchrotron. Longitudinally, the distribution is matched
116123
only in terms of linear focusing. For a non-linear bucket, the Gaussian
117124
distribution is cut along the separatrix (with some margin) and will
118125
gradually filament into the bucket. This will change the specified bunch
@@ -121,42 +128,50 @@ def generate_6D_Gaussian_bunch(self, n_macroparticles, intensity, epsn_x, epsn_y
121128
if self.longitudinal_focusing == 'linear':
122129
check_inside_bucket = lambda z,dp : np.array(len(z)*[True])
123130
elif self.longitudinal_focusing == 'non-linear':
124-
check_inside_bucket = self.longitudinal_map.get_bucket(self.gamma).make_is_accepted(margin = 0.05)
131+
check_inside_bucket = self.longitudinal_map.get_bucket(gamma=self.gamma).make_is_accepted(margin = 0.05)
125132
else:
126133
raise ValueError('Longitudinal_focusing not recognized!!!')
127134

128-
beta_z = self.eta*self.circumference/2./np.pi/self.Q_s
135+
beta_z = np.abs(self.eta)*self.circumference/2./np.pi/self.Q_s
129136
sigma_dp = sigma_z/beta_z
130137

131138
bunch = CutRFBucket6D(macroparticlenumber=n_macroparticles, intensity=intensity, charge=self.charge, mass=self.mass,
132-
circumference = self.circumference, gamma_reference=self.gamma,
139+
circumference = self.circumference, gamma=self.gamma,
133140
transverse_map=self.transverse_map, epsn_x=epsn_x, epsn_y=epsn_y,
134141
sigma_z=sigma_z, sigma_dp=sigma_dp,
135142
is_accepted=check_inside_bucket).generate()
136143

137144
if self.D_x[0] != 0:
138145
self.warns(('Correcting for (horizontal) dispersion {:g} m at first segment!\n').format(self.D_x[0]))
139146
bunch.x += bunch.dp*self.D_x[0]
147+
if self.D_y[0] != 0:
148+
self.warns(('Correcting for (vertical) dispersion {:g} m at first segment!\n').format(self.D_y[0]))
149+
bunch.y += bunch.dp*self.D_y[0]
150+
140151

141152
return bunch
142153

143-
def generate_6D_Gaussian_bunch_matched(self, n_macroparticles, intensity, epsn_x, epsn_y, sigma_z):
154+
def generate_6D_Gaussian_bunch_matched(self, n_macroparticles, intensity, epsn_x, epsn_y, sigma_z=None, epsn_z=None):
144155
'''
145156
Generates a 6D Gaussian distribution of particles which is transversely
146157
as well as longitudinally matched. The distribution is found iteratively
147158
to exactly yield the given bunch length while at the same time being
148159
stationary in the non-linear bucket. Thus, the bunch length should amount
149160
to the one specificed and should not change significantly during the
150-
synchrotron motion.
161+
Synchrotron motion.
151162
'''
152163
bunch = MatchRFBucket6D(macroparticlenumber=n_macroparticles, intensity=intensity,
153164
charge=self.charge, mass=self.mass,
154-
circumference=self.circumference, gamma_reference=self.gamma,
155-
epsn_x=epsn_x, epsn_y=epsn_y, sigma_z=sigma_z,
165+
circumference=self.circumference, gamma=self.gamma,
166+
epsn_x=epsn_x, epsn_y=epsn_y, epsn_z=epsn_z, sigma_z=sigma_z,
156167
transverse_map=self.transverse_map,
157-
rf_bucket=self.longitudinal_map.get_bucket(self.gamma)).generate()
168+
rf_bucket=self.longitudinal_map.get_bucket(gamma=self.gamma)).generate()
158169
if self.D_x[0] != 0:
159170
self.warns(('Correcting for (horizontal) dispersion {:g} m at first segment!\n').format(self.D_x[0]))
160171
bunch.x += bunch.dp*self.D_x[0]
172+
if self.D_y[0] != 0:
173+
self.warns(('Correcting for (vertical) dispersion {:g} m at first segment!\n').format(self.D_y[0]))
174+
bunch.y += bunch.dp*self.D_y[0]
175+
161176

162177
return bunch

0 commit comments

Comments
 (0)