syned 1.0.47__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- syned/__init__.py +0 -0
- syned/__test/__init__.py +46 -0
- syned/__test/test.py +28 -0
- syned/beamline/__init__.py +1 -0
- syned/beamline/beamline.py +155 -0
- syned/beamline/beamline_element.py +76 -0
- syned/beamline/element_coordinates.py +199 -0
- syned/beamline/optical_element.py +47 -0
- syned/beamline/optical_element_with_surface_shape.py +126 -0
- syned/beamline/optical_elements/__init__.py +1 -0
- syned/beamline/optical_elements/absorbers/__init__.py +0 -0
- syned/beamline/optical_elements/absorbers/absorber.py +21 -0
- syned/beamline/optical_elements/absorbers/beam_stopper.py +64 -0
- syned/beamline/optical_elements/absorbers/filter.py +61 -0
- syned/beamline/optical_elements/absorbers/holed_filter.py +67 -0
- syned/beamline/optical_elements/absorbers/slit.py +81 -0
- syned/beamline/optical_elements/crystals/__init__.py +1 -0
- syned/beamline/optical_elements/crystals/crystal.py +70 -0
- syned/beamline/optical_elements/gratings/__init__.py +1 -0
- syned/beamline/optical_elements/gratings/grating.py +279 -0
- syned/beamline/optical_elements/ideal_elements/__init__.py +1 -0
- syned/beamline/optical_elements/ideal_elements/ideal_element.py +16 -0
- syned/beamline/optical_elements/ideal_elements/ideal_fzp.py +183 -0
- syned/beamline/optical_elements/ideal_elements/ideal_lens.py +54 -0
- syned/beamline/optical_elements/ideal_elements/screen.py +16 -0
- syned/beamline/optical_elements/mirrors/__init__.py +1 -0
- syned/beamline/optical_elements/mirrors/mirror.py +39 -0
- syned/beamline/optical_elements/multilayers/__init__.py +46 -0
- syned/beamline/optical_elements/multilayers/multilayer.py +45 -0
- syned/beamline/optical_elements/refractors/__init__.py +1 -0
- syned/beamline/optical_elements/refractors/crl.py +79 -0
- syned/beamline/optical_elements/refractors/interface.py +61 -0
- syned/beamline/optical_elements/refractors/lens.py +105 -0
- syned/beamline/shape.py +2803 -0
- syned/storage_ring/__init__.py +1 -0
- syned/storage_ring/electron_beam.py +804 -0
- syned/storage_ring/empty_light_source.py +40 -0
- syned/storage_ring/light_source.py +90 -0
- syned/storage_ring/magnetic_structure.py +8 -0
- syned/storage_ring/magnetic_structures/__init__.py +1 -0
- syned/storage_ring/magnetic_structures/bending_magnet.py +329 -0
- syned/storage_ring/magnetic_structures/insertion_device.py +169 -0
- syned/storage_ring/magnetic_structures/undulator.py +413 -0
- syned/storage_ring/magnetic_structures/wiggler.py +27 -0
- syned/syned_object.py +264 -0
- syned/util/__init__.py +22 -0
- syned/util/json_tools.py +198 -0
- syned/widget/__init__.py +0 -0
- syned/widget/widget_decorator.py +67 -0
- syned-1.0.47.dist-info/METADATA +88 -0
- syned-1.0.47.dist-info/RECORD +54 -0
- syned-1.0.47.dist-info/WHEEL +5 -0
- syned-1.0.47.dist-info/licenses/LICENSE +20 -0
- syned-1.0.47.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,804 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base class for electron beams.
|
|
3
|
+
|
|
4
|
+
This class is intentionally shorten for simplicity.
|
|
5
|
+
Usually we would need to consider also the electron distribution within the beam.
|
|
6
|
+
"""
|
|
7
|
+
import scipy.constants as codata
|
|
8
|
+
import numpy
|
|
9
|
+
import warnings
|
|
10
|
+
|
|
11
|
+
from syned.util import deprecated
|
|
12
|
+
from syned.syned_object import SynedObject
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ElectronBeam(SynedObject):
|
|
16
|
+
def __init__(self,
|
|
17
|
+
energy_in_GeV = 1.0,
|
|
18
|
+
energy_spread = 0.0,
|
|
19
|
+
current = 0.1,
|
|
20
|
+
number_of_bunches = 400, # TODO: not used, to be removed (with care!)
|
|
21
|
+
moment_xx=0.0,
|
|
22
|
+
moment_xxp=0.0,
|
|
23
|
+
moment_xpxp=0.0,
|
|
24
|
+
moment_yy=0.0,
|
|
25
|
+
moment_yyp=0.0,
|
|
26
|
+
moment_ypyp=0.0,
|
|
27
|
+
dispersion_x=0.0,
|
|
28
|
+
dispersion_y=0.0,
|
|
29
|
+
dispersionp_x=0.0,
|
|
30
|
+
dispersionp_y=0.0
|
|
31
|
+
):
|
|
32
|
+
"""
|
|
33
|
+
Defines an electron beam at a given point of the storage ring.
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
energy_in_GeV : float, optional
|
|
38
|
+
The electron energy in GeV.
|
|
39
|
+
energy_spread : float, optional
|
|
40
|
+
The electron energy spread (in a fraction of the energy_in_GeV).
|
|
41
|
+
current : float, optional
|
|
42
|
+
The electron beam current intensity in A.
|
|
43
|
+
number_of_bunches : float, optional
|
|
44
|
+
The number of bunches in the storage ring.
|
|
45
|
+
moment_xx : float, optional
|
|
46
|
+
The <x^2> moment.
|
|
47
|
+
moment_xxp : float, optional
|
|
48
|
+
The <x x'> moment.
|
|
49
|
+
moment_xpxp : float, optional
|
|
50
|
+
The <x'^2> moment.
|
|
51
|
+
moment_yy : float, optional
|
|
52
|
+
The <y^2> moment.
|
|
53
|
+
moment_yyp : float, optional
|
|
54
|
+
The <y y'> moment.
|
|
55
|
+
moment_ypyp : float, optional
|
|
56
|
+
The <y'^2> moment.
|
|
57
|
+
dispersion_x : float, optional
|
|
58
|
+
The eta_x parameter, spatial dispersion
|
|
59
|
+
dispersion_y : float, optional
|
|
60
|
+
The eta_y parameter, spatial dispersion
|
|
61
|
+
dispersionp_x : float, optional
|
|
62
|
+
The eta'_x parameter, angular dispersion
|
|
63
|
+
dispersionp_y : float, optional
|
|
64
|
+
The eta'_y parameter, angular dispersion
|
|
65
|
+
"""
|
|
66
|
+
self._energy_in_GeV = energy_in_GeV
|
|
67
|
+
self._energy_spread = energy_spread
|
|
68
|
+
self._current = current
|
|
69
|
+
self._number_of_bunches = number_of_bunches
|
|
70
|
+
|
|
71
|
+
self._moment_xx = moment_xx
|
|
72
|
+
self._moment_xxp = moment_xxp
|
|
73
|
+
self._moment_xpxp = moment_xpxp
|
|
74
|
+
self._moment_yy = moment_yy
|
|
75
|
+
self._moment_yyp = moment_yyp
|
|
76
|
+
self._moment_ypyp = moment_ypyp
|
|
77
|
+
self._dispersion_x = dispersion_x
|
|
78
|
+
self._dispersion_y = dispersion_y
|
|
79
|
+
self._dispersionp_x = dispersionp_x
|
|
80
|
+
self._dispersionp_y = dispersionp_y
|
|
81
|
+
|
|
82
|
+
# support text containg name of variable, help text and unit. Will be stored in self._support_dictionary
|
|
83
|
+
self._set_support_text([
|
|
84
|
+
("energy_in_GeV" , "Electron beam energy" , "GeV" ),
|
|
85
|
+
("energy_spread" , "Electron beam energy spread (relative)", "" ),
|
|
86
|
+
("current" , "Electron beam current" , "A" ),
|
|
87
|
+
("number_of_bunches" , "Number of bunches" , "" ),
|
|
88
|
+
("moment_xx" , "Moment (spatial^2, horizontal)" , "m^2" ),
|
|
89
|
+
("moment_xxp" , "Moment (spatial-angular, horizontal)" , "m" ),
|
|
90
|
+
("moment_xpxp" , "Moment (angular^2, horizontal)" , "" ),
|
|
91
|
+
("moment_yy" , "Moment (spatial^2, vertical)" , "m^2" ),
|
|
92
|
+
("moment_yyp" , "Moment (spatial-angular, vertical)" , "m" ),
|
|
93
|
+
("moment_ypyp" , "Moment (angular^2, vertical)" , "" ),
|
|
94
|
+
("dispersion_x" , "Dispersion (horizontal)", ""),
|
|
95
|
+
("dispersion_y" , "Dispersion (vertical)", ""),
|
|
96
|
+
("dispersionp_x" , "Dispersion Derivative (horizontal)", ""),
|
|
97
|
+
("dispersionp_y" , "Dispersion Derivative (vertical)", ""),
|
|
98
|
+
] )
|
|
99
|
+
|
|
100
|
+
# ------------------------------------------------------------------------
|
|
101
|
+
# initializares and class methods
|
|
102
|
+
# ------------------------------------------------------------------------
|
|
103
|
+
|
|
104
|
+
@classmethod
|
|
105
|
+
def initialize_as_pencil_beam(cls, energy_in_GeV = 1.0, energy_spread = 0.0, current = 0.1, **params):
|
|
106
|
+
"""
|
|
107
|
+
Creates an electron pencil beam.
|
|
108
|
+
|
|
109
|
+
Parameters
|
|
110
|
+
----------
|
|
111
|
+
energy_in_GeV : float, optional
|
|
112
|
+
The electron energy in GeV.
|
|
113
|
+
energy_spread : float, optional
|
|
114
|
+
The electron energy spread (in a fraction of the energy_in_GeV).
|
|
115
|
+
current : float, optional
|
|
116
|
+
The electron beam current intensity in A.
|
|
117
|
+
params :
|
|
118
|
+
other keyword parameters accepted by ElectronBeam (if used, the result may not be a pencil beam.)
|
|
119
|
+
|
|
120
|
+
Returns
|
|
121
|
+
-------
|
|
122
|
+
instance of ElectronBeam
|
|
123
|
+
|
|
124
|
+
"""
|
|
125
|
+
return cls(energy_in_GeV=energy_in_GeV,
|
|
126
|
+
energy_spread=energy_spread,
|
|
127
|
+
current=current,
|
|
128
|
+
number_of_bunches=1,
|
|
129
|
+
**params)
|
|
130
|
+
|
|
131
|
+
@classmethod
|
|
132
|
+
def _emittance_without_dispersion(cls, moment_ss, moment_sa, moment_aa):
|
|
133
|
+
return float(numpy.sqrt(moment_ss * moment_aa - moment_sa**2))
|
|
134
|
+
|
|
135
|
+
@classmethod
|
|
136
|
+
def _emittance_with_dispersion(cls, moment_ss, moment_sa, moment_aa, energy_spread, dispersion_s, dispersion_a):
|
|
137
|
+
return float(numpy.sqrt((moment_ss + (dispersion_s * energy_spread) ** 2) *
|
|
138
|
+
(moment_aa + (dispersion_a * energy_spread) ** 2) -
|
|
139
|
+
(moment_sa + dispersion_s * dispersion_a * energy_spread ** 2) ** 2))
|
|
140
|
+
|
|
141
|
+
@classmethod
|
|
142
|
+
def _get_twiss_from_moments(cls, moment_ss, moment_sa, moment_aa):
|
|
143
|
+
emittance = cls._emittance_without_dispersion(moment_ss, moment_sa, moment_aa)
|
|
144
|
+
|
|
145
|
+
if emittance == 0.0:
|
|
146
|
+
warnings.warn(message="All moments are 0.0 and the calculation is not possible. \u03b5 = \u03b1 = \u03b2 = \u03b3 = 0.0 is returned.",
|
|
147
|
+
category=UserWarning, stacklevel=2)
|
|
148
|
+
return 0.0, 0.0, 0.0, 0.0
|
|
149
|
+
else:
|
|
150
|
+
alpha = -moment_sa / emittance
|
|
151
|
+
beta = moment_ss / emittance
|
|
152
|
+
gamma = (1 + alpha**2) / beta
|
|
153
|
+
|
|
154
|
+
alpha = 0.0 if alpha == 0 else alpha # to avoid -0.0
|
|
155
|
+
|
|
156
|
+
return emittance, alpha, beta, gamma
|
|
157
|
+
|
|
158
|
+
@classmethod
|
|
159
|
+
def _get_moments_from_twiss_without_dispersion(cls, emittance, alpha, beta):
|
|
160
|
+
if beta == 0:
|
|
161
|
+
warnings.warn(message="With \u03b2 = 0.0 the calculation of \u03b3 is not possible. \u03b3 = 0.0 is used.",
|
|
162
|
+
category=UserWarning, stacklevel=2)
|
|
163
|
+
gamma = 0.0
|
|
164
|
+
else:
|
|
165
|
+
gamma = (1 + alpha ** 2) / beta
|
|
166
|
+
|
|
167
|
+
moment_ss = beta * emittance
|
|
168
|
+
moment_sa = -alpha * emittance
|
|
169
|
+
moment_aa = gamma * emittance
|
|
170
|
+
|
|
171
|
+
moment_sa = 0.0 if moment_sa == 0 else moment_sa # to avoid -0.0
|
|
172
|
+
|
|
173
|
+
return float(moment_ss), float(moment_sa), float(moment_aa)
|
|
174
|
+
|
|
175
|
+
@classmethod
|
|
176
|
+
def _get_moments_with_dispersion(cls, moment_ss, moment_sa, moment_aa, energy_spread, dispersion_s, dispersion_a):
|
|
177
|
+
moment_ss_disp = moment_ss + (dispersion_s * energy_spread) ** 2
|
|
178
|
+
moment_sa_disp = moment_sa + dispersion_s * dispersion_a * (energy_spread ** 2)
|
|
179
|
+
moment_aa_disp = moment_aa + (dispersion_a * energy_spread) ** 2
|
|
180
|
+
|
|
181
|
+
return float(moment_ss_disp), float(moment_sa_disp), float(moment_aa_disp)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
# --- GETTERS
|
|
185
|
+
# # ---------------------------------------------------------------------------------------------------------------------------------------------
|
|
186
|
+
#
|
|
187
|
+
def get_sigmas_horizontal(self, dispersion=True):
|
|
188
|
+
"""
|
|
189
|
+
Returns the sigmas in horizontal direction.
|
|
190
|
+
|
|
191
|
+
Returns
|
|
192
|
+
-------
|
|
193
|
+
tuple
|
|
194
|
+
(sigma_x, sigma_x')
|
|
195
|
+
|
|
196
|
+
"""
|
|
197
|
+
|
|
198
|
+
moment_xx, _, moment_xpxp = self.get_moments_horizontal(dispersion)
|
|
199
|
+
|
|
200
|
+
return float(numpy.sqrt(moment_xx)), float(numpy.sqrt(moment_xpxp))
|
|
201
|
+
|
|
202
|
+
def get_sigmas_vertical(self, dispersion=True):
|
|
203
|
+
"""
|
|
204
|
+
Returns the sigmas in vertical direction.
|
|
205
|
+
|
|
206
|
+
Returns
|
|
207
|
+
-------
|
|
208
|
+
tuple
|
|
209
|
+
(sigma_y, sigma_y')
|
|
210
|
+
|
|
211
|
+
"""
|
|
212
|
+
moment_yy, _, moment_ypyp = self.get_moments_vertical(dispersion)
|
|
213
|
+
|
|
214
|
+
return float(numpy.sqrt(moment_yy)), float(numpy.sqrt(moment_ypyp))
|
|
215
|
+
|
|
216
|
+
def get_sigmas_all(self, dispersion=True):
|
|
217
|
+
"""
|
|
218
|
+
Returns all sigmas.
|
|
219
|
+
|
|
220
|
+
Returns
|
|
221
|
+
-------
|
|
222
|
+
tuple
|
|
223
|
+
(sigma_x, sigma_x', sigma_y, sigma_y')
|
|
224
|
+
|
|
225
|
+
"""
|
|
226
|
+
|
|
227
|
+
sigma_x, sigmap_x = self.get_sigmas_horizontal(dispersion)
|
|
228
|
+
sigma_y, sigmap_y = self.get_sigmas_vertical(dispersion)
|
|
229
|
+
|
|
230
|
+
return sigma_x, sigmap_x, sigma_y, sigmap_y
|
|
231
|
+
|
|
232
|
+
def get_moments_horizontal(self, dispersion=True):
|
|
233
|
+
"""
|
|
234
|
+
Returns the moments in the horizontal direction.
|
|
235
|
+
|
|
236
|
+
Returns
|
|
237
|
+
-------
|
|
238
|
+
tuple
|
|
239
|
+
( <x^2>, <x x'>, <x'^2>)
|
|
240
|
+
|
|
241
|
+
"""
|
|
242
|
+
if not dispersion: return float(self._moment_xx), float(self._moment_xxp), float(self._moment_xpxp)
|
|
243
|
+
else: return self._get_moments_with_dispersion(self._moment_xx,
|
|
244
|
+
self._moment_xxp,
|
|
245
|
+
self._moment_xpxp,
|
|
246
|
+
self._energy_spread,
|
|
247
|
+
self._dispersion_x,
|
|
248
|
+
self._dispersionp_x)
|
|
249
|
+
|
|
250
|
+
def get_moments_vertical(self, dispersion=True):
|
|
251
|
+
"""
|
|
252
|
+
Returns the moments in the vertical direction.
|
|
253
|
+
|
|
254
|
+
Returns
|
|
255
|
+
-------
|
|
256
|
+
tuple
|
|
257
|
+
( <y^2>, <y y'>, <y'^2>)
|
|
258
|
+
|
|
259
|
+
"""
|
|
260
|
+
|
|
261
|
+
if not dispersion: return float(self._moment_yy), float(self._moment_yyp), float(self._moment_ypyp)
|
|
262
|
+
else: return self._get_moments_with_dispersion(self._moment_yy,
|
|
263
|
+
self._moment_yyp,
|
|
264
|
+
self._moment_ypyp,
|
|
265
|
+
self._energy_spread,
|
|
266
|
+
self._dispersion_y,
|
|
267
|
+
self._dispersionp_y)
|
|
268
|
+
|
|
269
|
+
def get_moments_all(self, dispersion=True):
|
|
270
|
+
"""
|
|
271
|
+
Returns all moments.
|
|
272
|
+
|
|
273
|
+
Returns
|
|
274
|
+
-------
|
|
275
|
+
tuple
|
|
276
|
+
( <x^2>, <x x'>, <x'^2>, <y^2>, <y y'>, <y'^2>)
|
|
277
|
+
|
|
278
|
+
"""
|
|
279
|
+
|
|
280
|
+
moment_xx, moment_xxp, moment_xpxp = self.get_moments_horizontal(dispersion)
|
|
281
|
+
moment_yy, moment_yyp, moment_ypyp = self.get_moments_vertical(dispersion)
|
|
282
|
+
|
|
283
|
+
return moment_xx, moment_xxp, moment_xpxp, moment_yy, moment_yyp, moment_ypyp
|
|
284
|
+
|
|
285
|
+
def get_dispersion_horizontal(self):
|
|
286
|
+
return self._dispersion_x, self._dispersionp_x
|
|
287
|
+
|
|
288
|
+
def get_dispersion_vertical(self):
|
|
289
|
+
return self._dispersion_y, self._dispersionp_y
|
|
290
|
+
|
|
291
|
+
def get_dispersion_all(self):
|
|
292
|
+
dispersion_x, dispersionp_x = self.get_dispersion_horizontal()
|
|
293
|
+
dispersion_y, dispersionp_y = self.get_dispersion_vertical()
|
|
294
|
+
|
|
295
|
+
return dispersion_x, dispersionp_x, dispersion_y, dispersionp_y
|
|
296
|
+
|
|
297
|
+
def get_twiss_horizontal(self):
|
|
298
|
+
"""
|
|
299
|
+
Returns the Twiss parameters in horizontal direction.
|
|
300
|
+
(The energy disperion is considered.)
|
|
301
|
+
|
|
302
|
+
Returns
|
|
303
|
+
-------
|
|
304
|
+
tuple
|
|
305
|
+
(emittance_x, alpha_x, beta_x).
|
|
306
|
+
|
|
307
|
+
"""
|
|
308
|
+
|
|
309
|
+
ex, ax, bx, _ = self._get_twiss_from_moments(moment_ss=self._moment_xx,
|
|
310
|
+
moment_aa=self._moment_xpxp,
|
|
311
|
+
moment_sa=self._moment_xxp)
|
|
312
|
+
|
|
313
|
+
return ex, ax, bx
|
|
314
|
+
|
|
315
|
+
def get_twiss_vertical(self):
|
|
316
|
+
"""
|
|
317
|
+
Returns the Twiss parameters in vertical direction.
|
|
318
|
+
(The energy disperion is not considered.)
|
|
319
|
+
|
|
320
|
+
Returns
|
|
321
|
+
-------
|
|
322
|
+
tuple
|
|
323
|
+
(emittance_y, alpha_y, beta_y).
|
|
324
|
+
|
|
325
|
+
"""
|
|
326
|
+
ey, ay, by, _ = self._get_twiss_from_moments(moment_ss=self._moment_yy,
|
|
327
|
+
moment_aa=self._moment_ypyp,
|
|
328
|
+
moment_sa=self._moment_yyp)
|
|
329
|
+
|
|
330
|
+
return ey, ay, by
|
|
331
|
+
|
|
332
|
+
def get_twiss_all(self):
|
|
333
|
+
"""
|
|
334
|
+
Returns all Twiss parameters.
|
|
335
|
+
(The energy disperion is not considered.)
|
|
336
|
+
|
|
337
|
+
Returns
|
|
338
|
+
-------
|
|
339
|
+
tuple
|
|
340
|
+
(emittance_x, alpha_x, beta_x, emittance_y, alpha_y, beta_y).
|
|
341
|
+
|
|
342
|
+
"""
|
|
343
|
+
ex, ax, bx = self.get_twiss_horizontal()
|
|
344
|
+
ey, ay, by = self.get_twiss_vertical()
|
|
345
|
+
|
|
346
|
+
return ex, ax, bx, ey, ay, by
|
|
347
|
+
|
|
348
|
+
def energy(self):
|
|
349
|
+
"""
|
|
350
|
+
Returns the electron energy in GeV.
|
|
351
|
+
|
|
352
|
+
Returns
|
|
353
|
+
-------
|
|
354
|
+
float
|
|
355
|
+
|
|
356
|
+
"""
|
|
357
|
+
return self._energy_in_GeV
|
|
358
|
+
|
|
359
|
+
def current(self):
|
|
360
|
+
"""
|
|
361
|
+
Returns the electron current in A.
|
|
362
|
+
|
|
363
|
+
Returns
|
|
364
|
+
-------
|
|
365
|
+
float
|
|
366
|
+
|
|
367
|
+
"""
|
|
368
|
+
return self._current
|
|
369
|
+
|
|
370
|
+
def set_sigmas_horizontal(self, sigma_x=0.0, sigma_xp=0.0):
|
|
371
|
+
"""
|
|
372
|
+
Sets the electron beam parameters from the sigma values in horizontal direction.
|
|
373
|
+
|
|
374
|
+
Parameters
|
|
375
|
+
----------
|
|
376
|
+
sigma_x : float, optional
|
|
377
|
+
The sigma in real space.
|
|
378
|
+
sigma_xp : float, optional
|
|
379
|
+
The sigma in divergence space.
|
|
380
|
+
|
|
381
|
+
"""
|
|
382
|
+
self.set_moments_horizontal(moment_xx=sigma_x ** 2, moment_xxp=0.0, moment_xpxp=sigma_xp ** 2)
|
|
383
|
+
|
|
384
|
+
def set_sigmas_vertical(self, sigma_y=0.0, sigma_yp=0.0):
|
|
385
|
+
"""
|
|
386
|
+
Sets the electron beam parameters from the sigma values in vertical direction.
|
|
387
|
+
|
|
388
|
+
Parameters
|
|
389
|
+
----------
|
|
390
|
+
sigma_y : float, optional
|
|
391
|
+
The sigma in real space.
|
|
392
|
+
sigma_yp : float, optional
|
|
393
|
+
The sigma in divergence space.
|
|
394
|
+
|
|
395
|
+
"""
|
|
396
|
+
|
|
397
|
+
self.set_moments_vertical(moment_yy=sigma_y**2, moment_yyp=0.0, moment_ypyp=sigma_yp**2)
|
|
398
|
+
|
|
399
|
+
def set_sigmas_all(self, sigma_x=0.0, sigma_xp=0.0, sigma_y=0.0, sigma_yp=0.0):
|
|
400
|
+
"""
|
|
401
|
+
Sets the electron beam parameters from the sigma values in both horizontal and vertical direction.
|
|
402
|
+
|
|
403
|
+
Parameters
|
|
404
|
+
----------
|
|
405
|
+
sigma_x : float, optional
|
|
406
|
+
The sigma in real space (horizontal).
|
|
407
|
+
sigma_xp : float, optional
|
|
408
|
+
The sigma in divergence space (horizontal).
|
|
409
|
+
sigma_y : float, optional
|
|
410
|
+
The sigma in real space (vertical).
|
|
411
|
+
sigma_yp : float, optional
|
|
412
|
+
The sigma in divergence space (vertical).
|
|
413
|
+
|
|
414
|
+
"""
|
|
415
|
+
self.set_sigmas_horizontal(sigma_x, sigma_xp)
|
|
416
|
+
self.set_sigmas_vertical( sigma_y, sigma_yp)
|
|
417
|
+
|
|
418
|
+
def set_energy_from_gamma(self, gamma):
|
|
419
|
+
"""
|
|
420
|
+
Sets the electron energy from the gamma value (Lorentz factor).
|
|
421
|
+
|
|
422
|
+
Parameters
|
|
423
|
+
----------
|
|
424
|
+
gamma : float
|
|
425
|
+
|
|
426
|
+
"""
|
|
427
|
+
self._energy_in_GeV = (gamma / 1e9) * (codata.m_e * codata.c**2 / codata.e)
|
|
428
|
+
|
|
429
|
+
def set_moments_horizontal(self, moment_xx, moment_xxp, moment_xpxp):
|
|
430
|
+
"""
|
|
431
|
+
Sets the moments in the horizontal direction.
|
|
432
|
+
|
|
433
|
+
Parameters
|
|
434
|
+
----------
|
|
435
|
+
moment_xx : float
|
|
436
|
+
The <x^2> moment.
|
|
437
|
+
moment_xxp : float
|
|
438
|
+
The <x x'> moment.
|
|
439
|
+
moment_xpxp : float,
|
|
440
|
+
The <x'^2> moment.
|
|
441
|
+
|
|
442
|
+
"""
|
|
443
|
+
self._moment_xx = moment_xx
|
|
444
|
+
self._moment_xxp = moment_xxp
|
|
445
|
+
self._moment_xpxp = moment_xpxp
|
|
446
|
+
|
|
447
|
+
def set_moments_vertical(self, moment_yy, moment_yyp, moment_ypyp):
|
|
448
|
+
"""
|
|
449
|
+
Sets the moments in the vertical direction.
|
|
450
|
+
|
|
451
|
+
Parameters
|
|
452
|
+
----------
|
|
453
|
+
moment_yy : float
|
|
454
|
+
The <y^2> moment.
|
|
455
|
+
moment_yyp : float
|
|
456
|
+
The <y y'> moment.
|
|
457
|
+
moment_ypyp : float
|
|
458
|
+
The <y'^2> moment.
|
|
459
|
+
|
|
460
|
+
"""
|
|
461
|
+
self._moment_yy = moment_yy
|
|
462
|
+
self._moment_yyp = moment_yyp
|
|
463
|
+
self._moment_ypyp = moment_ypyp
|
|
464
|
+
|
|
465
|
+
def set_moments_all(self, moment_xx, moment_xxp, moment_xpxp, moment_yy, moment_yyp, moment_ypyp):
|
|
466
|
+
"""
|
|
467
|
+
Sets the moments.
|
|
468
|
+
|
|
469
|
+
Parameters
|
|
470
|
+
----------
|
|
471
|
+
moment_xx : float
|
|
472
|
+
The <x^2> moment.
|
|
473
|
+
moment_xxp : float
|
|
474
|
+
The <x x'> moment.
|
|
475
|
+
moment_xpxp : float,
|
|
476
|
+
The <x'^2> moment.
|
|
477
|
+
moment_yy : float
|
|
478
|
+
The <y^2> moment.
|
|
479
|
+
moment_yyp : float
|
|
480
|
+
The <y y'> moment.
|
|
481
|
+
moment_ypyp : float
|
|
482
|
+
The <y'^2> moment.
|
|
483
|
+
|
|
484
|
+
"""
|
|
485
|
+
self.set_moments_horizontal(moment_xx, moment_xxp, moment_xpxp)
|
|
486
|
+
self.set_moments_vertical(moment_yy, moment_yyp, moment_ypyp)
|
|
487
|
+
|
|
488
|
+
def set_dispersion_horizontal(self, eta_x, etap_x):
|
|
489
|
+
"""
|
|
490
|
+
Sets the horizontal dispersion values.
|
|
491
|
+
|
|
492
|
+
Parameters
|
|
493
|
+
----------
|
|
494
|
+
eta_x : float
|
|
495
|
+
The eta value in horizontal.
|
|
496
|
+
etap_x : float
|
|
497
|
+
The eta' value in horizontal.
|
|
498
|
+
"""
|
|
499
|
+
self._dispersion_x = eta_x
|
|
500
|
+
self._dispersionp_x = etap_x
|
|
501
|
+
|
|
502
|
+
def set_dispersion_vertical(self, eta_y, etap_y):
|
|
503
|
+
"""
|
|
504
|
+
Sets the vertical dispersion values.
|
|
505
|
+
|
|
506
|
+
Parameters
|
|
507
|
+
----------
|
|
508
|
+
eta_y : float
|
|
509
|
+
The eta value in vertical.
|
|
510
|
+
etap_y : float
|
|
511
|
+
The eta' value in vertical.
|
|
512
|
+
|
|
513
|
+
"""
|
|
514
|
+
self._dispersion_y = eta_y
|
|
515
|
+
self._dispersionp_y = etap_y
|
|
516
|
+
|
|
517
|
+
def set_dispersion_all(self, eta_x, etap_x, eta_y, etap_y):
|
|
518
|
+
"""
|
|
519
|
+
Sets the dispersion values.
|
|
520
|
+
|
|
521
|
+
Parameters
|
|
522
|
+
----------
|
|
523
|
+
eta_x : float
|
|
524
|
+
The eta value in horizontal.
|
|
525
|
+
etap_x : float
|
|
526
|
+
The eta' value in horizontal.
|
|
527
|
+
eta_y : float
|
|
528
|
+
The eta value in vertical.
|
|
529
|
+
etap_y : float
|
|
530
|
+
The eta' value in vertical.
|
|
531
|
+
|
|
532
|
+
"""
|
|
533
|
+
self.set_dispersion_horizontal(eta_x, etap_x)
|
|
534
|
+
self.set_dispersion_vertical(eta_y, etap_y)
|
|
535
|
+
|
|
536
|
+
def set_twiss_horizontal(self, emittance_x, alpha_x, beta_x, **kwargs):
|
|
537
|
+
"""
|
|
538
|
+
Sets the electron beam parameters from the Twiss values in the horizontal direction.
|
|
539
|
+
|
|
540
|
+
Parameters
|
|
541
|
+
----------
|
|
542
|
+
emittance_x : float
|
|
543
|
+
The emittance value in horizontal.
|
|
544
|
+
alpha_x : float
|
|
545
|
+
The alpha value in horizontal.
|
|
546
|
+
beta_x : float
|
|
547
|
+
The beta value in horizontal.
|
|
548
|
+
eta_x : float, optional
|
|
549
|
+
The eta value in horizontal.
|
|
550
|
+
etap_x : float, optional
|
|
551
|
+
The eta' value in horizontal.
|
|
552
|
+
|
|
553
|
+
"""
|
|
554
|
+
moment_xx, moment_xxp, moment_xpxp = self._get_moments_from_twiss_without_dispersion(emittance_x, alpha_x, beta_x)
|
|
555
|
+
|
|
556
|
+
self._moment_xx = moment_xx
|
|
557
|
+
self._moment_xxp = moment_xxp
|
|
558
|
+
self._moment_xpxp = moment_xpxp
|
|
559
|
+
|
|
560
|
+
# RETROCOMPATIBILITY
|
|
561
|
+
eta_x = kwargs.get("eta_x", 0.0)
|
|
562
|
+
etap_x = kwargs.get("etap_x", 0.0)
|
|
563
|
+
|
|
564
|
+
if eta_x != 0.0 or etap_x != 0.0:
|
|
565
|
+
warnings.warn(message="Setting dispersion parameters with `set_twiss_horizontal(..., eta_x, etap_x)` is deprecated "
|
|
566
|
+
"and will be removed in a future version. "
|
|
567
|
+
"Use `set_dispersion_horizontal(eta_x, etap_x)` separately instead.",
|
|
568
|
+
category=DeprecationWarning, stacklevel=2)
|
|
569
|
+
self.set_dispersion_horizontal(0.0 if eta_x is None else eta_x,
|
|
570
|
+
0.0 if etap_x is None else etap_x)
|
|
571
|
+
|
|
572
|
+
def set_twiss_vertical(self, emittance_y, alpha_y, beta_y, **kwargs):
|
|
573
|
+
"""
|
|
574
|
+
Sets the electron beam parameters from the Twiss values in the vertical direction.
|
|
575
|
+
|
|
576
|
+
Parameters
|
|
577
|
+
----------
|
|
578
|
+
emittance_y : float
|
|
579
|
+
The emittance value in vertical.
|
|
580
|
+
alpha_x : float
|
|
581
|
+
The alpha value in vertical.
|
|
582
|
+
beta_x : float
|
|
583
|
+
The beta value in vertical.
|
|
584
|
+
eta_x : float, optional
|
|
585
|
+
The eta value.
|
|
586
|
+
etap_x : float, optional
|
|
587
|
+
The eta' value in vertical.
|
|
588
|
+
|
|
589
|
+
"""
|
|
590
|
+
moment_yy, moment_yyp, moment_ypyp = self._get_moments_from_twiss_without_dispersion(emittance_y, alpha_y, beta_y)
|
|
591
|
+
|
|
592
|
+
self._moment_yy = moment_yy
|
|
593
|
+
self._moment_yyp = moment_yyp
|
|
594
|
+
self._moment_ypyp = moment_ypyp
|
|
595
|
+
|
|
596
|
+
# RETROCOMPATIBILITY
|
|
597
|
+
eta_y = kwargs.get("eta_y", 0.0)
|
|
598
|
+
etap_y = kwargs.get("etap_y", 0.0)
|
|
599
|
+
|
|
600
|
+
if eta_y != 0.0 or etap_y != 0.0:
|
|
601
|
+
warnings.warn(message="Setting dispersion parameters with `set_twiss_vertical(..., eta_y, etap_y)` is deprecated "
|
|
602
|
+
"and will be removed in a future version. "
|
|
603
|
+
"Use `set_dispersion_vertical(eta_y, etap_y)` separately instead.",
|
|
604
|
+
category=DeprecationWarning, stacklevel=2)
|
|
605
|
+
|
|
606
|
+
self.set_dispersion_vertical(0.0 if eta_y is None else eta_y,
|
|
607
|
+
0.0 if etap_y is None else etap_y)
|
|
608
|
+
|
|
609
|
+
def set_twiss_all(self, emittance_x, alpha_x, beta_x, emittance_y, alpha_y, beta_y, **kwargs):
|
|
610
|
+
"""
|
|
611
|
+
Sets the electron beam parameters from the Twiss values.
|
|
612
|
+
|
|
613
|
+
Parameters
|
|
614
|
+
----------
|
|
615
|
+
emittance_x : float
|
|
616
|
+
The emittance value in horizontal.
|
|
617
|
+
alpha_x : float
|
|
618
|
+
The alpha value in horizontal.
|
|
619
|
+
beta_x : float
|
|
620
|
+
The beta value in horizontal.
|
|
621
|
+
emittance_y : float
|
|
622
|
+
The emittance value in vertical.
|
|
623
|
+
alpha_y : float
|
|
624
|
+
The alpha value in vertical.
|
|
625
|
+
beta_y : float
|
|
626
|
+
The beta value in vertical.
|
|
627
|
+
|
|
628
|
+
"""
|
|
629
|
+
self.set_twiss_horizontal(emittance_x, alpha_x, beta_x, **kwargs)
|
|
630
|
+
self.set_twiss_vertical(emittance_y, alpha_y, beta_y, **kwargs)
|
|
631
|
+
|
|
632
|
+
#
|
|
633
|
+
# some easy calculations
|
|
634
|
+
#
|
|
635
|
+
def gamma(self):
|
|
636
|
+
"""
|
|
637
|
+
returns the Gamma or Lorentz factor.
|
|
638
|
+
|
|
639
|
+
Returns
|
|
640
|
+
-------
|
|
641
|
+
float
|
|
642
|
+
|
|
643
|
+
"""
|
|
644
|
+
return self.lorentz_factor()
|
|
645
|
+
|
|
646
|
+
def lorentz_factor(self):
|
|
647
|
+
"""
|
|
648
|
+
returns the Gamma or Lorentz factor.
|
|
649
|
+
|
|
650
|
+
Returns
|
|
651
|
+
-------
|
|
652
|
+
float
|
|
653
|
+
|
|
654
|
+
"""
|
|
655
|
+
return 1e9 * self._energy_in_GeV / (codata.m_e * codata.c**2 / codata.e)
|
|
656
|
+
|
|
657
|
+
def electron_speed(self):
|
|
658
|
+
"""
|
|
659
|
+
Returns the electron velocity in c units.
|
|
660
|
+
|
|
661
|
+
Returns
|
|
662
|
+
-------
|
|
663
|
+
float
|
|
664
|
+
|
|
665
|
+
"""
|
|
666
|
+
return numpy.sqrt(1.0 - 1.0 / self.lorentz_factor() ** 2)
|
|
667
|
+
|
|
668
|
+
def emittance(self, dispersion=True):
|
|
669
|
+
if not dispersion:
|
|
670
|
+
emittance_x = self._emittance_without_dispersion(self._moment_xx, self._moment_xxp, self._moment_xpxp)
|
|
671
|
+
emittance_y = self._emittance_without_dispersion(self._moment_yy, self._moment_yyp, self._moment_ypyp)
|
|
672
|
+
else:
|
|
673
|
+
emittance_x = self._emittance_with_dispersion(self._moment_xx, self._moment_xxp, self._moment_xpxp, self._energy_spread, self._dispersion_x, self._dispersionp_x)
|
|
674
|
+
emittance_y = self._emittance_with_dispersion(self._moment_yy, self._moment_yyp, self._moment_ypyp, self._energy_spread, self._dispersion_y, self._dispersionp_y)
|
|
675
|
+
|
|
676
|
+
return emittance_x, emittance_y
|
|
677
|
+
|
|
678
|
+
#
|
|
679
|
+
# dictionnary interface, info etc
|
|
680
|
+
#
|
|
681
|
+
def has_dispersion(self):
|
|
682
|
+
return (self._dispersion_x != 0 or
|
|
683
|
+
self._dispersion_y != 0 or
|
|
684
|
+
self._dispersionp_x != 0 or
|
|
685
|
+
self._dispersionp_y != 0)
|
|
686
|
+
|
|
687
|
+
#
|
|
688
|
+
# backcompatibility (deprecated)
|
|
689
|
+
#
|
|
690
|
+
@deprecated("Use `get_twiss_all()` instead")
|
|
691
|
+
def get_twiss_no_dispersion_all(self): return self.get_twiss_all()
|
|
692
|
+
|
|
693
|
+
@deprecated("Use `get_twiss_horizontal()` instead")
|
|
694
|
+
def get_twiss_no_dispersion_horizontal(self): return self.get_twiss_horizontal()
|
|
695
|
+
|
|
696
|
+
@deprecated("Use `get_twiss_vertical()` instead")
|
|
697
|
+
def get_twiss_no_dispersion_vertical(self): return self.get_twiss_vertical()
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
if __name__ == "__main__":
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
# checks
|
|
704
|
+
|
|
705
|
+
if 1: # twiss
|
|
706
|
+
a = ElectronBeam.initialize_as_pencil_beam(energy_in_GeV=2.0, current=0.5, energy_spread=0.00095)
|
|
707
|
+
|
|
708
|
+
# Twiss emittance, alpha, beta, gamma
|
|
709
|
+
e_x = 70e-12
|
|
710
|
+
a_x = 0.827
|
|
711
|
+
b_x = 0.34
|
|
712
|
+
eta_x = 0.0031
|
|
713
|
+
etap_x = -0.06
|
|
714
|
+
e_y = 70e-12
|
|
715
|
+
a_y = -10.7
|
|
716
|
+
b_y = 24.26
|
|
717
|
+
eta_y = 0.0
|
|
718
|
+
etap_y = 0.0
|
|
719
|
+
|
|
720
|
+
a.set_twiss_horizontal(e_x, a_x, b_x, eta_x=eta_x, etap_x=etap_x)
|
|
721
|
+
a.set_twiss_vertical(e_y, a_y, b_y, eta_y=eta_y, etap_y=etap_y)
|
|
722
|
+
# a.set_dispersion_all(eta_x=eta_x, etap_x=etap_x, eta_y=eta_y, etap_y=etap_y)
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
print("INPUTS: ")
|
|
726
|
+
print("H twiss data: emittance, alpha, beta", e_x, a_x, b_x) #
|
|
727
|
+
print("V twiss data: emittance, alpha, beta", e_y, a_y, b_y) # , eta_y, etap_y)
|
|
728
|
+
print("H dispersion data: eta, eta'", eta_x, etap_x)
|
|
729
|
+
print("V dispersion data: eta, eta'", eta_y, etap_y)
|
|
730
|
+
|
|
731
|
+
print("NO DISPERSION: ")
|
|
732
|
+
print("twiss H: ", a.get_twiss_horizontal())
|
|
733
|
+
print("twiss V: ", a.get_twiss_vertical())
|
|
734
|
+
print("twiss H, V: ", a.get_twiss_all())
|
|
735
|
+
print("sigmas H, V: ", a.get_sigmas_all())
|
|
736
|
+
print("moments H, V: ", a.get_moments_all())
|
|
737
|
+
|
|
738
|
+
print("WITH DISPERSION: ")
|
|
739
|
+
print("twiss H: ", a.get_twiss_horizontal())
|
|
740
|
+
print("twiss V: ", a.get_twiss_vertical())
|
|
741
|
+
print("twiss H, V: ", a.get_twiss_all())
|
|
742
|
+
print("sigmas H, V: ", a.get_sigmas_all(dispersion=True))
|
|
743
|
+
print("moments H, V: ", a.get_moments_all(dispersion=True))
|
|
744
|
+
|
|
745
|
+
if 1: # moments, sigmas
|
|
746
|
+
|
|
747
|
+
print(">>>> set moments (alpha=0): 1e-6,0,9e-6,16e-6,0,36e-6")
|
|
748
|
+
a = ElectronBeam.initialize_as_pencil_beam(energy_in_GeV=2.0, current=0.5, energy_spread=0.00095)
|
|
749
|
+
a.set_moments_all(1e-6, 0, 9e-6, 16e-6, 0, 36e-6)
|
|
750
|
+
print("has_dispersion: ", a.has_dispersion())
|
|
751
|
+
print("moments: ", a.get_moments_all(dispersion=True))
|
|
752
|
+
print("sigmas: ", a.get_sigmas_all(dispersion=True))
|
|
753
|
+
|
|
754
|
+
print(">>>> set sigmas (alpha=0): 1e-6,2e-6,3e-6")
|
|
755
|
+
a = ElectronBeam.initialize_as_pencil_beam(energy_in_GeV=2.0, current=0.5, energy_spread=0.00095)
|
|
756
|
+
a.set_sigmas_all(1e-6, 2e-6, 3e-6, 4e-6)
|
|
757
|
+
print("has_dispersion: ", a.has_dispersion())
|
|
758
|
+
print("moments: ", a.get_moments_all(dispersion=True))
|
|
759
|
+
print("sigmas: ", a.get_sigmas_all(dispersion=True))
|
|
760
|
+
|
|
761
|
+
print(">>>> set moments (alpha!=0): 1e-6,4e-6,9e-6,16e-6,25e-6,36e-6")
|
|
762
|
+
a = ElectronBeam.initialize_as_pencil_beam(energy_in_GeV=2.0, current=0.5, energy_spread=0.00095)
|
|
763
|
+
a.set_moments_all(1e-6, 4e-6, 9e-6, 16e-6, 25e-6, 36e-6)
|
|
764
|
+
print("has_dispersion: ", a.has_dispersion())
|
|
765
|
+
print("moments: ", a.get_moments_all(dispersion=True))
|
|
766
|
+
print("sigmas: ", a.get_sigmas_all(dispersion=True))
|
|
767
|
+
|
|
768
|
+
if 1: # ESRF-ID01 (checked vs Accelerator Tools)
|
|
769
|
+
|
|
770
|
+
e_x = 1.41e-10
|
|
771
|
+
e_y = 1e-11
|
|
772
|
+
a_x = -0.0022927
|
|
773
|
+
a_y = -0.0010488
|
|
774
|
+
b_x = 6.8987
|
|
775
|
+
b_y = 2.6589
|
|
776
|
+
eta_x = 0.0014291
|
|
777
|
+
eta_y = -3.1352e-18
|
|
778
|
+
etap_x = -3.1205e-06
|
|
779
|
+
etap_y = 1.7067e-18
|
|
780
|
+
a = ElectronBeam.initialize_as_pencil_beam(energy_in_GeV=6.0, current=0.2, energy_spread=0.00095)
|
|
781
|
+
a.set_twiss_horizontal(e_x, a_x, b_x) # , eta_x, etap_x)
|
|
782
|
+
a.set_twiss_vertical(e_y, a_y, b_y) # , eta_y, etap_y)
|
|
783
|
+
a.set_dispersion_all(eta_x=eta_x, etap_x=etap_x, eta_y=eta_y, etap_y=etap_y)
|
|
784
|
+
|
|
785
|
+
gammaX = 0.14496
|
|
786
|
+
gammaY = 0.37609
|
|
787
|
+
|
|
788
|
+
|
|
789
|
+
print("has_dispersion: ", a.has_dispersion())
|
|
790
|
+
print("Twiss: ", a.get_twiss_all())
|
|
791
|
+
# xx = 9.734e-10
|
|
792
|
+
# xxp = 3.1889e-13
|
|
793
|
+
# xpxp = 2.0415e-11
|
|
794
|
+
# yy = 2.6589e-11
|
|
795
|
+
# yyp = 1.0488e-14
|
|
796
|
+
# ypyp = 3.7609e-12
|
|
797
|
+
print("moments (with dispersion): ", a.get_moments_all(dispersion=True))
|
|
798
|
+
print("moments (without dispersion): ", a.get_moments_all(dispersion=True))
|
|
799
|
+
# sigma x = 3.1199e-05
|
|
800
|
+
# sigma x' = 4.5183e-06
|
|
801
|
+
# sigma y = 5.1565e-06
|
|
802
|
+
# sigma y' = 1.9393e-06
|
|
803
|
+
print("sigmas (with dispersion): ", a.get_sigmas_all(dispersion=True))
|
|
804
|
+
print("sigmas (without dispersion): ", a.get_sigmas_all(dispersion=True))
|