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.
Files changed (54) hide show
  1. syned/__init__.py +0 -0
  2. syned/__test/__init__.py +46 -0
  3. syned/__test/test.py +28 -0
  4. syned/beamline/__init__.py +1 -0
  5. syned/beamline/beamline.py +155 -0
  6. syned/beamline/beamline_element.py +76 -0
  7. syned/beamline/element_coordinates.py +199 -0
  8. syned/beamline/optical_element.py +47 -0
  9. syned/beamline/optical_element_with_surface_shape.py +126 -0
  10. syned/beamline/optical_elements/__init__.py +1 -0
  11. syned/beamline/optical_elements/absorbers/__init__.py +0 -0
  12. syned/beamline/optical_elements/absorbers/absorber.py +21 -0
  13. syned/beamline/optical_elements/absorbers/beam_stopper.py +64 -0
  14. syned/beamline/optical_elements/absorbers/filter.py +61 -0
  15. syned/beamline/optical_elements/absorbers/holed_filter.py +67 -0
  16. syned/beamline/optical_elements/absorbers/slit.py +81 -0
  17. syned/beamline/optical_elements/crystals/__init__.py +1 -0
  18. syned/beamline/optical_elements/crystals/crystal.py +70 -0
  19. syned/beamline/optical_elements/gratings/__init__.py +1 -0
  20. syned/beamline/optical_elements/gratings/grating.py +279 -0
  21. syned/beamline/optical_elements/ideal_elements/__init__.py +1 -0
  22. syned/beamline/optical_elements/ideal_elements/ideal_element.py +16 -0
  23. syned/beamline/optical_elements/ideal_elements/ideal_fzp.py +183 -0
  24. syned/beamline/optical_elements/ideal_elements/ideal_lens.py +54 -0
  25. syned/beamline/optical_elements/ideal_elements/screen.py +16 -0
  26. syned/beamline/optical_elements/mirrors/__init__.py +1 -0
  27. syned/beamline/optical_elements/mirrors/mirror.py +39 -0
  28. syned/beamline/optical_elements/multilayers/__init__.py +46 -0
  29. syned/beamline/optical_elements/multilayers/multilayer.py +45 -0
  30. syned/beamline/optical_elements/refractors/__init__.py +1 -0
  31. syned/beamline/optical_elements/refractors/crl.py +79 -0
  32. syned/beamline/optical_elements/refractors/interface.py +61 -0
  33. syned/beamline/optical_elements/refractors/lens.py +105 -0
  34. syned/beamline/shape.py +2803 -0
  35. syned/storage_ring/__init__.py +1 -0
  36. syned/storage_ring/electron_beam.py +804 -0
  37. syned/storage_ring/empty_light_source.py +40 -0
  38. syned/storage_ring/light_source.py +90 -0
  39. syned/storage_ring/magnetic_structure.py +8 -0
  40. syned/storage_ring/magnetic_structures/__init__.py +1 -0
  41. syned/storage_ring/magnetic_structures/bending_magnet.py +329 -0
  42. syned/storage_ring/magnetic_structures/insertion_device.py +169 -0
  43. syned/storage_ring/magnetic_structures/undulator.py +413 -0
  44. syned/storage_ring/magnetic_structures/wiggler.py +27 -0
  45. syned/syned_object.py +264 -0
  46. syned/util/__init__.py +22 -0
  47. syned/util/json_tools.py +198 -0
  48. syned/widget/__init__.py +0 -0
  49. syned/widget/widget_decorator.py +67 -0
  50. syned-1.0.47.dist-info/METADATA +88 -0
  51. syned-1.0.47.dist-info/RECORD +54 -0
  52. syned-1.0.47.dist-info/WHEEL +5 -0
  53. syned-1.0.47.dist-info/licenses/LICENSE +20 -0
  54. 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))