Skip to content

Commit 1e6a1a9

Browse files
authored
Merge pull request #30 from giadarol/develop
Testing and some fixes from Hannes and myself
2 parents 376d2ca + c1cd7bb commit 1e6a1a9

File tree

7 files changed

+185
-56
lines changed

7 files changed

+185
-56
lines changed

examples/load_from_mad/002_compare_against_sixinput.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
lmad = pysixtrack.Line.from_dict(pickle.load(fid))
1010

1111
sixinput = sixtracktools.sixinput.SixInput("sixtrack/")
12-
lsix, other = pysixtrack.Line.from_sixinput(sixinput)
12+
lsix = pysixtrack.Line.from_sixinput(sixinput)
1313

1414
original_length = lmad.get_length()
1515
assert (lsix.get_length() - original_length) < 1e-6

pysixtrack/be_beamfields/beambeam.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import numpy as np
12
from scipy.constants import e as qe
23
from scipy.constants import c as clight
34

@@ -17,9 +18,9 @@ class BeamBeam4D(Element):
1718
"Charge of the interacting distribution (strong beam)",
1819
0,
1920
),
20-
("sigma_x", "m", "Horizontal size of the strong beam (r.m.s.)", 0),
21-
("sigma_y", "m", "Vertical size of the strong beam (r.m.s.)", 0),
22-
("beta_r", "", "Relativistic beta of the stron beam", 0),
21+
("sigma_x", "m", "Horizontal size of the strong beam (r.m.s.)", 1.0),
22+
("sigma_y", "m", "Vertical size of the strong beam (r.m.s.)", 1.0),
23+
("beta_r", "", "Relativistic beta of the stron beam", 1.0),
2324
(
2425
"x_bb",
2526
"m",
@@ -112,20 +113,20 @@ class BeamBeam6D(Element):
112113
"charge_slices",
113114
"qe",
114115
"Charge of the interacting slices (strong beam)",
115-
(),
116+
(0.0),
116117
),
117118
(
118119
"zeta_slices",
119120
"m",
120121
"Longitudinal position of the interacting"
121122
"slices (>0 head of the strong).",
122-
(),
123+
(0.0),
123124
),
124125
(
125126
"sigma_11",
126127
"m^2",
127128
"Sigma_11 element of the sigma matrix of the strong beam",
128-
0,
129+
1.0,
129130
),
130131
(
131132
"sigma_12",
@@ -167,7 +168,7 @@ class BeamBeam6D(Element):
167168
"sigma_33",
168169
"m^2",
169170
"Sigma_33 element of the sigma matrix of the strong beam",
170-
0,
171+
1.0,
171172
),
172173
(
173174
"sigma_34",
@@ -223,8 +224,8 @@ def track(self, p):
223224
self.alpha,
224225
self.x_bb_co,
225226
self.y_bb_co,
226-
self.charge_slices,
227-
self.zeta_slices,
227+
np.atleast_1d(self.charge_slices),
228+
np.atleast_1d(self.zeta_slices),
228229
self.sigma_11,
229230
self.sigma_12,
230231
self.sigma_13,

pysixtrack/be_beamfields/gaussian_fields.py

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -123,32 +123,36 @@ def _get_Ex_Ey_Gx_Gy_gauss(
123123
)
124124

125125
if not skip_Gs:
126-
Gx = (
127-
1
128-
/ (2.0 * (x * x + y * y))
129-
* (
130-
y * Ey
131-
- x * Ex
132-
+ 1.0
133-
/ (2 * pi * epsilon_0 * sigma * sigma)
134-
* x
135-
* x
136-
* exp(-(x * x + y * y) / (2.0 * sigma * sigma))
126+
if abs(x) + abs(y) < min_sigma_diff:
127+
Gx = 0.0
128+
Gy = 0.0
129+
else:
130+
Gx = (
131+
1
132+
/ (2.0 * (x * x + y * y))
133+
* (
134+
y * Ey
135+
- x * Ex
136+
+ 1.0
137+
/ (2 * pi * epsilon_0 * sigma * sigma)
138+
* x
139+
* x
140+
* exp(-(x * x + y * y) / (2.0 * sigma * sigma))
141+
)
137142
)
138-
)
139-
Gy = (
140-
1.0
141-
/ (2 * (x * x + y * y))
142-
* (
143-
x * Ex
144-
- y * Ey
145-
+ 1.0
146-
/ (2 * pi * epsilon_0 * sigma * sigma)
147-
* y
148-
* y
149-
* exp(-(x * x + y * y) / (2.0 * sigma * sigma))
143+
Gy = (
144+
1.0
145+
/ (2 * (x * x + y * y))
146+
* (
147+
x * Ex
148+
- y * Ey
149+
+ 1.0
150+
/ (2 * pi * epsilon_0 * sigma * sigma)
151+
* y
152+
* y
153+
* exp(-(x * x + y * y) / (2.0 * sigma * sigma))
154+
)
150155
)
151-
)
152156
else:
153157

154158
sigma_x = sigma_x

pysixtrack/be_beamfields/spacecharge.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ class SpaceChargeCoasting(Element):
66
"""Space charge for a coasting beam"""
77

88
_description = [
9-
("line_density", "1/m", "Desc...", 0.0),
10-
("sigma_x", "m", "Desc...", 1.0),
11-
("sigma_y", "m", "Desc...", 1.0),
12-
("length", "m", "Desc...", 0.0),
13-
("x_co", "m", "Desc...", 0.0),
14-
("y_co", "m", "Desc...", 0),
9+
("line_density", "1/m", "Number of particles per unit length", 0.0),
10+
("sigma_x", "m", "Horizontal size of the beam (r.m.s.)", 1.0),
11+
("sigma_y", "m", "Vertical size of the beam (r.m.s.)", 1.0),
12+
("length", "m", "Integration length of space charge kick", 0.0),
13+
("x_co", "m", "Horizontal closed orbit offset", 0.0),
14+
("y_co", "m", "Vertical closed orbit offset", 0),
1515
]
1616
_extra = [
17-
("min_sigma_diff", "m", "Desc...", 1e-30),
18-
("enabled", "", "Desc...", True),
17+
("min_sigma_diff", "m", "Threshold to detect round beam", 1e-30),
18+
("enabled", "", "Switch to disable space charge effect", True),
1919
]
2020

2121
def track(self, p):
@@ -64,17 +64,17 @@ def track(self, p):
6464

6565
class SpaceChargeBunched(Element):
6666
_description = [
67-
("number_of_particles", "", "Desc...", 0.0),
68-
("bunchlength_rms", "m", "Desc...", 1.0),
69-
("sigma_x", "m", "Desc...", 1.0),
70-
("sigma_y", "m", "Desc...", 1.0),
71-
("length", "m", "Desc...", 0.0),
72-
("x_co", "m", "Desc...", 0.0),
73-
("y_co", "m", "Desc...", 0),
67+
("number_of_particles", "", "Number of particles in the bunch", 0.0),
68+
("bunchlength_rms", "m", "Length of the bunch (r.m.s.)", 1.0),
69+
("sigma_x", "m", "Horizontal size of the beam (r.m.s.)", 1.0),
70+
("sigma_y", "m", "Vertical size of the beam (r.m.s.)", 1.0),
71+
("length", "m", "Integration length of space charge kick", 0.0),
72+
("x_co", "m", "Horizontal closed orbit offset", 0.0),
73+
("y_co", "m", "Vertical closed orbit offset", 0),
7474
]
7575
_extra = [
76-
("min_sigma_diff", "m", "Desc...", 1e-30),
77-
("enabled", "", "Desc...", True),
76+
("min_sigma_diff", "m", "Threshold to detect round beam", 1e-30),
77+
("enabled", "", "Switch to disable space charge effect", True),
7878
]
7979

8080
def track(self, p):

pysixtrack/elements.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ def track(self, particle):
309309
and y <= self.max_y
310310
)
311311
if particle.state != 1:
312-
return particle.state
312+
return "Particle lost"
313313
else:
314314
particle.state = np.int_(
315315
(x >= self.min_x)
@@ -319,13 +319,13 @@ def track(self, particle):
319319
)
320320
particle.remove_lost_particles()
321321
if len(particle.state) == 0:
322-
return -1
322+
return "All particles lost"
323323

324324

325325
class LimitEllipse(Element):
326326
_description = [
327-
("a", "m^2", "Horizontal semiaxis", 1.0),
328-
("b", "m^2", "Vertical semiaxis", 1.0),
327+
("a", "m", "Horizontal semiaxis", 1.0),
328+
("b", "m", "Vertical semiaxis", 1.0),
329329
]
330330

331331
def track(self, particle):
@@ -345,7 +345,7 @@ def track(self, particle):
345345
)
346346
particle.remove_lost_particles()
347347
if len(particle.state) == 0:
348-
return "All particle lost"
348+
return "All particles lost"
349349

350350

351351
class BeamMonitor(Element):

tests/test_beamfields.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import numpy as np
2+
3+
import pysixtrack
4+
5+
6+
def test_track_spacecharge():
7+
x_co = 0.1
8+
y_co = -0.5
9+
sigma_x = 0.5
10+
sigma_y = 0.1
11+
el1 = pysixtrack.elements.SpaceChargeBunched(
12+
number_of_particles=1e11,
13+
bunchlength_rms=0.22,
14+
sigma_x=sigma_x,
15+
sigma_y=sigma_y,
16+
length=2.0,
17+
x_co=x_co,
18+
y_co=y_co,
19+
)
20+
line_density = el1.number_of_particles / (
21+
el1.bunchlength_rms * np.sqrt(2 * np.pi)
22+
)
23+
el2 = pysixtrack.elements.SpaceChargeCoasting(
24+
line_density=line_density,
25+
sigma_x=el1.sigma_x,
26+
sigma_y=el1.sigma_y,
27+
length=el1.length,
28+
x_co=el1.x_co,
29+
y_co=el1.y_co,
30+
)
31+
32+
# test absolute kick for sigma_x > sigma_y
33+
x_offset = 0.2
34+
y_offset = -0.5
35+
p1 = pysixtrack.Particles()
36+
p1.x = x_co + x_offset
37+
p1.y = y_co + y_offset
38+
p2 = p1.copy()
39+
el1.track(p1)
40+
el2.track(p2)
41+
assert np.isclose(p1.px, 1.33671170365656e-07, atol=1e-15)
42+
assert np.isclose(p1.py, -6.228154616877465e-07, atol=1e-15)
43+
assert p1.compare(p2, abs_tol=1e-15)
44+
45+
# test absolute kick for sigma_y > sigma_x
46+
el1.sigma_x = sigma_y
47+
el1.sigma_y = sigma_x
48+
el2.sigma_x = sigma_y
49+
el2.sigma_y = sigma_x
50+
p1 = pysixtrack.Particles()
51+
p1.x = x_co + y_offset
52+
p1.y = y_co + x_offset
53+
p2 = p1.copy()
54+
el1.track(p1)
55+
el2.track(p2)
56+
assert np.isclose(p1.px, -6.228154616877465e-07, atol=1e-15)
57+
assert np.isclose(p1.py, 1.33671170365656e-07, atol=1e-15)
58+
assert p1.compare(p2, abs_tol=1e-15)
59+
60+
# test no kick for particle on closed orbit
61+
p1 = pysixtrack.Particles()
62+
p1.x = el1.x_co
63+
p1.y = el1.y_co
64+
p2 = p1.copy()
65+
el1.track(p1)
66+
el2.track(p2)
67+
assert np.isclose(p1.px, 0.0, atol=1e-15)
68+
assert np.isclose(p1.py, 0.0, atol=1e-15)
69+
assert p1.compare(p2, abs_tol=1e-15)

tests/test_track.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
import numpy as np
2+
13
import pysixtrack
24

35
element_list = [
46
pysixtrack.elements.Drift,
57
pysixtrack.elements.DriftExact,
68
pysixtrack.elements.Multipole,
79
pysixtrack.elements.Cavity,
10+
pysixtrack.elements.SawtoothCavity,
811
pysixtrack.elements.XYShift,
912
pysixtrack.elements.SRotation,
1013
pysixtrack.elements.RFMultipole,
@@ -13,6 +16,10 @@
1316
pysixtrack.elements.Line,
1417
pysixtrack.elements.LimitRect,
1518
pysixtrack.elements.LimitEllipse,
19+
pysixtrack.elements.BeamBeam4D,
20+
pysixtrack.elements.BeamBeam6D,
21+
pysixtrack.elements.SpaceChargeCoasting,
22+
pysixtrack.elements.SpaceChargeBunched,
1623
]
1724

1825

@@ -35,3 +42,51 @@ def test_track_rfmultipole():
3542
el2.track(p2)
3643

3744
assert p1.compare(p2, abs_tol=1e-15)
45+
46+
47+
def test_track_LimitRect():
48+
min_x = -0.1
49+
max_x = 0.3
50+
min_y = -0.5
51+
max_y = 0.1
52+
el = pysixtrack.elements.LimitRect(
53+
min_x=min_x, max_x=max_x, min_y=min_y, max_y=max_y
54+
)
55+
56+
p1 = pysixtrack.Particles()
57+
p1.x = 1
58+
p1.y = 1
59+
ret = el.track(p1)
60+
assert ret == "Particle lost"
61+
62+
arr = np.arange(0, 1, 0.001)
63+
p2 = pysixtrack.Particles(x=arr, y=arr)
64+
ret = el.track(p2)
65+
66+
p2.x += max_x + 1e-6
67+
ret = el.track(p2)
68+
assert ret == "All particles lost"
69+
70+
71+
def test_track_LimitEllipse():
72+
limit_a = 0.1
73+
limit_b = 0.2
74+
el = pysixtrack.elements.LimitEllipse(a=limit_a, b=limit_b)
75+
76+
p1 = pysixtrack.Particles()
77+
p1.x = 1
78+
p1.y = 1
79+
ret = el.track(p1)
80+
assert ret == "Particle lost"
81+
82+
arr = np.arange(0, 1, 0.001)
83+
p2 = pysixtrack.Particles(x=arr, y=arr)
84+
ret = el.track(p2)
85+
survived = np.where(
86+
(p2.x ** 2 / limit_a ** 2 + p2.y ** 2 / limit_b ** 2 <= 1.0)
87+
)
88+
assert len(p2.state) == len(survived[0])
89+
90+
p2.x += limit_a + 1e-6
91+
ret = el.track(p2)
92+
assert ret == "All particles lost"

0 commit comments

Comments
 (0)