xfields 0.23.2__tar.gz → 0.24.0__tar.gz

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 (117) hide show
  1. {xfields-0.23.2 → xfields-0.24.0}/PKG-INFO +1 -1
  2. {xfields-0.23.2 → xfields-0.24.0}/tests/test_electroncloud.py +10 -3
  3. xfields-0.24.0/tests/test_ibs_equilibrium.py +326 -0
  4. xfields-0.24.0/xfields/_version.py +1 -0
  5. {xfields-0.23.2 → xfields-0.24.0}/xfields/config_tools/electroncloud_config_tools.py +7 -5
  6. {xfields-0.23.2 → xfields-0.24.0}/xfields/config_tools/spacecharge_config_tools.py +3 -2
  7. {xfields-0.23.2 → xfields-0.24.0}/xfields/ibs/__init__.py +2 -0
  8. {xfields-0.23.2 → xfields-0.24.0}/xfields/ibs/_api.py +1 -1
  9. xfields-0.24.0/xfields/ibs/_equilibrium.py +552 -0
  10. {xfields-0.23.2 → xfields-0.24.0}/xfields.egg-info/PKG-INFO +1 -1
  11. {xfields-0.23.2 → xfields-0.24.0}/xfields.egg-info/SOURCES.txt +2 -0
  12. xfields-0.23.2/xfields/_version.py +0 -1
  13. {xfields-0.23.2 → xfields-0.24.0}/LICENSE +0 -0
  14. {xfields-0.23.2 → xfields-0.24.0}/MANIFEST.in +0 -0
  15. {xfields-0.23.2 → xfields-0.24.0}/README.md +0 -0
  16. {xfields-0.23.2 → xfields-0.24.0}/pyproject.toml +0 -0
  17. {xfields-0.23.2 → xfields-0.24.0}/setup.cfg +0 -0
  18. {xfields-0.23.2 → xfields-0.24.0}/setup.py +0 -0
  19. {xfields-0.23.2 → xfields-0.24.0}/tests/test_alpha_pi_setter.py +0 -0
  20. {xfields-0.23.2 → xfields-0.24.0}/tests/test_beambeam2d.py +0 -0
  21. {xfields-0.23.2 → xfields-0.24.0}/tests/test_beambeam3d_part1.py +0 -0
  22. {xfields-0.23.2 → xfields-0.24.0}/tests/test_beambeam3d_part2.py +0 -0
  23. {xfields-0.23.2 → xfields-0.24.0}/tests/test_beambeam_pic.py +0 -0
  24. {xfields-0.23.2 → xfields-0.24.0}/tests/test_beambeamstrongstrong2d.py +0 -0
  25. {xfields-0.23.2 → xfields-0.24.0}/tests/test_beambeamstrongstrong2d_pi.py +0 -0
  26. {xfields-0.23.2 → xfields-0.24.0}/tests/test_beambeamstrongstrong3d.py +0 -0
  27. {xfields-0.23.2 → xfields-0.24.0}/tests/test_beambeamstrongstrong3d_pi.py +0 -0
  28. {xfields-0.23.2 → xfields-0.24.0}/tests/test_beamstrahlung.py +0 -0
  29. {xfields-0.23.2 → xfields-0.24.0}/tests/test_beamstrahlung_pic.py +0 -0
  30. {xfields-0.23.2 → xfields-0.24.0}/tests/test_bhabha.py +0 -0
  31. {xfields-0.23.2 → xfields-0.24.0}/tests/test_cerrf.py +0 -0
  32. {xfields-0.23.2 → xfields-0.24.0}/tests/test_compressed_profile_interp_result.py +0 -0
  33. {xfields-0.23.2 → xfields-0.24.0}/tests/test_constant_charge_slicing.py +0 -0
  34. {xfields-0.23.2 → xfields-0.24.0}/tests/test_electronlens_interpolated.py +0 -0
  35. {xfields-0.23.2 → xfields-0.24.0}/tests/test_element_with_slicer_filling_scheme.py +0 -0
  36. {xfields-0.23.2 → xfields-0.24.0}/tests/test_ibs_growth_rates.py +0 -0
  37. {xfields-0.23.2 → xfields-0.24.0}/tests/test_ibs_kicks.py +0 -0
  38. {xfields-0.23.2 → xfields-0.24.0}/tests/test_iptocp_strongstrong.py +0 -0
  39. {xfields-0.23.2 → xfields-0.24.0}/tests/test_lumi.py +0 -0
  40. {xfields-0.23.2 → xfields-0.24.0}/tests/test_mean_std.py +0 -0
  41. {xfields-0.23.2 → xfields-0.24.0}/tests/test_profiles.py +0 -0
  42. {xfields-0.23.2 → xfields-0.24.0}/tests/test_slicer.py +0 -0
  43. {xfields-0.23.2 → xfields-0.24.0}/tests/test_spacecharge.py +0 -0
  44. {xfields-0.23.2 → xfields-0.24.0}/tests/test_temp_slicer.py +0 -0
  45. {xfields-0.23.2 → xfields-0.24.0}/xfields/__init__.py +0 -0
  46. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/__init__.py +0 -0
  47. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam2d.py +0 -0
  48. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam3d.py +0 -0
  49. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam3dpic.py +0 -0
  50. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam_src/beambeam.h +0 -0
  51. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam_src/beambeam2d.h +0 -0
  52. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam_src/beambeam3d.h +0 -0
  53. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam_src/beambeam3d_methods_for_strongstrong.h +0 -0
  54. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam_src/beambeam3d_ref_frame_changes.h +0 -0
  55. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam_src/beambeam3d_transport_sigmas.h +0 -0
  56. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam_src/beambeampic_methods.h +0 -0
  57. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/electroncloud.py +0 -0
  58. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/electroncloud_src/electroncloud.h +0 -0
  59. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/electronlens_interpolated.py +0 -0
  60. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/electronlens_src/electronlens_interpolated.h +0 -0
  61. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/element_with_slicer.py +0 -0
  62. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/spacecharge.py +0 -0
  63. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/spacecharge_src/spacecharge3d.h +0 -0
  64. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/spacecharge_src/spacechargebigaussian.h +0 -0
  65. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/temp_slicer.py +0 -0
  66. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/waketracker/__init__.py +0 -0
  67. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/waketracker/convolution.py +0 -0
  68. {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/waketracker/waketracker.py +0 -0
  69. {xfields-0.23.2 → xfields-0.24.0}/xfields/config_tools/__init__.py +0 -0
  70. {xfields-0.23.2 → xfields-0.24.0}/xfields/config_tools/beambeam_config_tools/__init__.py +0 -0
  71. {xfields-0.23.2 → xfields-0.24.0}/xfields/config_tools/beambeam_config_tools/_madpoint.py +0 -0
  72. {xfields-0.23.2 → xfields-0.24.0}/xfields/config_tools/beambeam_config_tools/config_tools.py +0 -0
  73. {xfields-0.23.2 → xfields-0.24.0}/xfields/config_tools/beambeam_config_tools/orbit_dependent_configuration_tools.py +0 -0
  74. {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/__init__.py +0 -0
  75. {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/bigaussian.py +0 -0
  76. {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/bigaussian_src/bigaussian.h +0 -0
  77. {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/bigaussian_src/bigaussian_fieldmap.h +0 -0
  78. {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/bigaussian_src/compute_gx_gy.h +0 -0
  79. {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/bigaussian_src/faddeeva.h +0 -0
  80. {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/bigaussian_src/faddeeva_cernlib.h +0 -0
  81. {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/bigaussian_src/faddeeva_mit.h +0 -0
  82. {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/interpolated.py +0 -0
  83. {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/interpolated_src/central_diff.h +0 -0
  84. {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/interpolated_src/charge_deposition.h +0 -0
  85. {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/interpolated_src/cubic_interpolators.h +0 -0
  86. {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/interpolated_src/linear_interpolators.h +0 -0
  87. {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/interpolated_src/tricubic_coefficients.h +0 -0
  88. {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/tricubicinterpolated.py +0 -0
  89. {xfields-0.23.2 → xfields-0.24.0}/xfields/general.py +0 -0
  90. {xfields-0.23.2 → xfields-0.24.0}/xfields/headers/beamstrahlung_spectrum.h +0 -0
  91. {xfields-0.23.2 → xfields-0.24.0}/xfields/headers/beamstrahlung_spectrum_pic.h +0 -0
  92. {xfields-0.23.2 → xfields-0.24.0}/xfields/headers/bhabha_spectrum.h +0 -0
  93. {xfields-0.23.2 → xfields-0.24.0}/xfields/headers/compressed_profile.h +0 -0
  94. {xfields-0.23.2 → xfields-0.24.0}/xfields/headers/compute_slice_moments.h +0 -0
  95. {xfields-0.23.2 → xfields-0.24.0}/xfields/headers/constants.h +0 -0
  96. {xfields-0.23.2 → xfields-0.24.0}/xfields/headers/particle_states.h +0 -0
  97. {xfields-0.23.2 → xfields-0.24.0}/xfields/headers/power_n.h +0 -0
  98. {xfields-0.23.2 → xfields-0.24.0}/xfields/headers/sincos.h +0 -0
  99. {xfields-0.23.2 → xfields-0.24.0}/xfields/ibs/_analytical.py +0 -0
  100. {xfields-0.23.2 → xfields-0.24.0}/xfields/ibs/_formulary.py +0 -0
  101. {xfields-0.23.2 → xfields-0.24.0}/xfields/ibs/_kicks.py +0 -0
  102. {xfields-0.23.2 → xfields-0.24.0}/xfields/longitudinal_profiles/__init__.py +0 -0
  103. {xfields-0.23.2 → xfields-0.24.0}/xfields/longitudinal_profiles/coasting.py +0 -0
  104. {xfields-0.23.2 → xfields-0.24.0}/xfields/longitudinal_profiles/qgaussian.py +0 -0
  105. {xfields-0.23.2 → xfields-0.24.0}/xfields/longitudinal_profiles/qgaussian_src/qgaussian.h +0 -0
  106. {xfields-0.23.2 → xfields-0.24.0}/xfields/slicers/__init__.py +0 -0
  107. {xfields-0.23.2 → xfields-0.24.0}/xfields/slicers/compressed_profile.py +0 -0
  108. {xfields-0.23.2 → xfields-0.24.0}/xfields/slicers/slicers_src/uniform_bin_slicer.h +0 -0
  109. {xfields-0.23.2 → xfields-0.24.0}/xfields/slicers/uniform.py +0 -0
  110. {xfields-0.23.2 → xfields-0.24.0}/xfields/solvers/__init__.py +0 -0
  111. {xfields-0.23.2 → xfields-0.24.0}/xfields/solvers/base.py +0 -0
  112. {xfields-0.23.2 → xfields-0.24.0}/xfields/solvers/fftsolvers.py +0 -0
  113. {xfields-0.23.2 → xfields-0.24.0}/xfields/test_support/__init__.py +0 -0
  114. {xfields-0.23.2 → xfields-0.24.0}/xfields/test_support/temp_makepart.py +0 -0
  115. {xfields-0.23.2 → xfields-0.24.0}/xfields.egg-info/dependency_links.txt +0 -0
  116. {xfields-0.23.2 → xfields-0.24.0}/xfields.egg-info/requires.txt +0 -0
  117. {xfields-0.23.2 → xfields-0.24.0}/xfields.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xfields
3
- Version: 0.23.2
3
+ Version: 0.24.0
4
4
  Summary: Field Maps and Particle In Cell
5
5
  Home-page: https://xsuite.readthedocs.io/
6
6
  Download-URL: https://pypi.python.org/pypi/xfields
@@ -119,9 +119,16 @@ def test_electroncloud_config(test_context):
119
119
  'mqd': {key: ecloud_info['mqd'][key] for key in list(ecloud_info['mqd'].keys())[:5]}
120
120
  }
121
121
 
122
- twiss_without_ecloud, twiss_with_ecloud = xf.full_electroncloud_setup(line=line,
123
- ecloud_info=reduced_ecloud_info, filenames=pinch_filenames, context=test_context, zeta_max=zeta_max)
124
-
122
+ twiss_without_ecloud, twiss_with_ecloud = xf.full_electroncloud_setup(line=line,
123
+ ecloud_info=reduced_ecloud_info, filenames=pinch_filenames,
124
+ context=test_context, zeta_max=zeta_max)
125
125
 
126
126
  xo.assert_allclose(twiss_with_ecloud['x'],twiss_without_ecloud['x'], atol=3e-12, rtol=0)
127
127
  xo.assert_allclose(twiss_with_ecloud['y'],twiss_without_ecloud['y'], atol=3e-12, rtol=0)
128
+
129
+ tt = line.get_table()
130
+ assert np.all(tt.rows[tt.element_type == 'ElectronCloud'].name == np.array(
131
+ ['ecloud.mqd.12.0', 'ecloud.mqf.12.0', 'ecloud.mqd.12.1',
132
+ 'ecloud.mqf.12.1', 'ecloud.mqd.12.10', 'ecloud.mqf.12.10',
133
+ 'ecloud.mqd.12.11', 'ecloud.mqf.12.11', 'ecloud.mqd.12.12',
134
+ 'ecloud.mqf.12.12']))
@@ -0,0 +1,326 @@
1
+ import pytest
2
+ import xobjects as xo
3
+ import xtrack as xt
4
+ from ibs_conftest import XTRACK_TEST_DATA
5
+
6
+ BUNCH_INTENSITY: float = 6.2e9 # 1C bunch intensity
7
+
8
+
9
+ # ----- Fixture for the (configured) BESSY III line ----- #
10
+
11
+
12
+ @pytest.fixture(scope="module")
13
+ def bessy3_line_with_radiation() -> xt.Line:
14
+ """
15
+ Loads the BESSY III lattice as a Line and
16
+ configures radiation before returning it.
17
+ """
18
+ # -------------------------------------------
19
+ # Load the line with a particle_ref
20
+ bess3_dir = XTRACK_TEST_DATA / "bessy3"
21
+ linefile = bess3_dir / "bessy3.json"
22
+ line = xt.Line.from_json(linefile)
23
+ # -------------------------------------------
24
+ # Build tracker and configure radiation
25
+ line.build_tracker()
26
+ line.matrix_stability_tol = 1e-2
27
+ line.configure_radiation(model="mean")
28
+ line.compensate_radiation_energy_loss()
29
+ # Run twiss in fixture to compile kernels once
30
+ line.twiss(eneloss_and_damping=True)
31
+ return line
32
+
33
+
34
+ # ----- Test Functions vs Analytical Formulae ----- #
35
+
36
+
37
+ @pytest.mark.parametrize("emittance_coupling_factor", [0.02, 0.1, 1.0])
38
+ def test_equilibrium_vs_analytical_constraint_coupling(
39
+ emittance_coupling_factor: float, bessy3_line_with_radiation: xt.Line
40
+ ):
41
+ """
42
+ Load the BESSY III line and compute ierations until we reach
43
+ an equilibrium with SR and IBS, in the case where we enforce
44
+ a betatron coupling constraint on the transverse planes. The
45
+ resulting values are tested against an analytical estimate.
46
+ """
47
+ # -------------------------------------------
48
+ # Get the twiss with SR effects from the configured line
49
+ tw = bessy3_line_with_radiation.twiss(eneloss_and_damping=True)
50
+ # -------------------------------------------
51
+ # Compute the equilibrium emittances - coupling constraint
52
+ result = tw.get_ibs_and_synrad_emittance_evolution(
53
+ formalism="nagaitsev", # No Dy in the line, faster
54
+ total_beam_intensity=BUNCH_INTENSITY,
55
+ emittance_coupling_factor=emittance_coupling_factor,
56
+ emittance_constraint="coupling",
57
+ )
58
+ # -------------------------------------------
59
+ # Check results vs analytical estimations (uses last step's growth rate!)
60
+ factor = 1 + emittance_coupling_factor * (tw.partition_numbers[1] / tw.partition_numbers[0])
61
+ # Check the horizontal equilibrium emittance
62
+ xo.assert_allclose(
63
+ result.eq_sr_ibs_gemitt_x,
64
+ result.gemitt_x[0] / (1 - result.Kx[-1] / (tw.damping_constants_s[0] * factor)),
65
+ rtol=1e-2,
66
+ )
67
+ # Check the emittance coupling constraint (also checks vert. eq. emittance)
68
+ xo.assert_allclose(result.gemitt_y / result.gemitt_x, emittance_coupling_factor, rtol=1e-2)
69
+ # Check the longitudinal equilibrium emittance
70
+ xo.assert_allclose(
71
+ result.eq_sr_ibs_gemitt_zeta,
72
+ result.gemitt_zeta[0] / (1 - result.Kz[-1] / (tw.damping_constants_s[2])),
73
+ rtol=1e-2,
74
+ )
75
+
76
+
77
+ @pytest.mark.parametrize("emittance_coupling_factor", [0.02, 0.1, 1.0])
78
+ def test_equilibrium_vs_analytical_constraint_excitation(
79
+ emittance_coupling_factor: float, bessy3_line_with_radiation: xt.Line
80
+ ):
81
+ """
82
+ Load the BESSY III line and compute ierations until we reach
83
+ an equilibrium with SR and IBS, in the case where we enforce
84
+ an excitation type constraint on the transverse planes. The
85
+ resulting values are tested against an analytical estimate.
86
+ """
87
+ # -------------------------------------------
88
+ # Get the twiss with SR effects from the configured line
89
+ tw = bessy3_line_with_radiation.twiss(eneloss_and_damping=True)
90
+ # -------------------------------------------
91
+ # Compute the equilibrium emittances - excitation constraint
92
+ result = tw.get_ibs_and_synrad_emittance_evolution(
93
+ formalism="nagaitsev", # No Dy in the line, faster
94
+ total_beam_intensity=BUNCH_INTENSITY,
95
+ emittance_coupling_factor=emittance_coupling_factor,
96
+ emittance_constraint="excitation",
97
+ )
98
+ # -------------------------------------------
99
+ # Check results vs analytical estimations (uses last step's growth rate!)
100
+ # Check the horizontal equilibrium emittance
101
+ xo.assert_allclose(
102
+ result.eq_sr_ibs_gemitt_x,
103
+ result.gemitt_x[0] / (1 - result.Kx[-1] / tw.damping_constants_s[0]),
104
+ rtol=1e-2,
105
+ )
106
+ # Check the emittance coupling constraint (also checks vert. eq. emittance)
107
+ xo.assert_allclose(result.gemitt_y / result.gemitt_x, emittance_coupling_factor, rtol=1e-2)
108
+ # Check the longitudinal equilibrium emittance
109
+ xo.assert_allclose(
110
+ result.eq_sr_ibs_gemitt_zeta,
111
+ result.gemitt_zeta[0] / (1 - result.Kz[-1] / (tw.damping_constants_s[2])),
112
+ rtol=1e-2,
113
+ )
114
+
115
+
116
+ # This factor should not be too high as otherwise the starting
117
+ # vertical emittance will be way out of realistic values
118
+ @pytest.mark.parametrize("initial_factor", [0.01, 0.02, 0.05])
119
+ def test_equilibrium_vs_analytical_no_constraint(
120
+ initial_factor: float, bessy3_line_with_radiation: xt.Line
121
+ ):
122
+ """
123
+ Load the BESSY III line and compute ierations until we reach
124
+ an equilibrium with SR and IBS, whithout any constraint on
125
+ the transverse planes. In that case, the equilibrium emittance
126
+ becomes almost identical to the solution of the differential
127
+ equation describing the emittance evolution in presence of IBS
128
+ and SR.
129
+ """
130
+ # -------------------------------------------
131
+ # Get the twiss with SR effects from the configured line
132
+ tw = bessy3_line_with_radiation.twiss(eneloss_and_damping=True)
133
+ # -------------------------------------------
134
+ # Compute the equilibrium emittances - no constraint
135
+ # No constraint so no renormalization of transverse emittances
136
+ # and SR eq in vertical is 0 so we change it to avoid exact 0
137
+ result = tw.get_ibs_and_synrad_emittance_evolution(
138
+ formalism="nagaitsev", # No Dy in the line, faster
139
+ total_beam_intensity=BUNCH_INTENSITY,
140
+ gemitt_x=tw.eq_gemitt_x,
141
+ gemitt_y=tw.eq_gemitt_x * initial_factor,
142
+ gemitt_zeta=tw.eq_gemitt_zeta,
143
+ emittance_constraint=None,
144
+ )
145
+ # -------------------------------------------
146
+ # Check results vs analytical estimations (uses last step's growth rate!)
147
+ # Check the horizontal equilibrium emittance
148
+ xo.assert_allclose(
149
+ result.eq_sr_ibs_gemitt_x,
150
+ result.gemitt_x[0] / (1 - result.Kx[-1] / tw.damping_constants_s[0]),
151
+ rtol=1e-2,
152
+ )
153
+ # Check the vertical equilibrium emittance
154
+ xo.assert_allclose(
155
+ result.eq_sr_ibs_gemitt_y,
156
+ result.gemitt_y[0] / (1 - result.Ky[-1] / tw.damping_constants_s[1]),
157
+ rtol=1e-2,
158
+ )
159
+ # Check the longitudinal equilibrium emittance
160
+ xo.assert_allclose(
161
+ result.eq_sr_ibs_gemitt_zeta,
162
+ result.gemitt_zeta[0] / (1 - result.Kz[-1] / (tw.damping_constants_s[2])),
163
+ rtol=1e-2,
164
+ )
165
+
166
+
167
+ # ----- Test Functions vs ELEGANT Results ----- #
168
+
169
+ # Ugly hardcoded results from ELEGANT. The keys here
170
+ # are emittance coupling factor and associated are the
171
+ # corresponding final values we want to compare to.
172
+ # ELEGANT gives IBS rates in emittance convention!
173
+ ELEGANT_RESULTS: dict[float, dict[str, float]] = {
174
+ 0.02: {
175
+ "eps_x": 1.88319e-10,
176
+ "sigma_z": 0.00491982,
177
+ "sigma_delta": 0.00140017,
178
+ "T_x": 106.648,
179
+ "T_z": 32.8772,
180
+ },
181
+ 0.1: {
182
+ "eps_x": 1.46119e-10,
183
+ "sigma_z": 0.00441742,
184
+ "sigma_delta": 0.00125719,
185
+ "T_x": 81.5391,
186
+ "T_z": 25.2408,
187
+ },
188
+ 0.5: {
189
+ "eps_x": 1.05835e-10,
190
+ "sigma_z": 0.00404997,
191
+ "sigma_delta": 0.00115261,
192
+ "T_x": 63.7394,
193
+ "T_z": 17.7664,
194
+ },
195
+ 1: {
196
+ "eps_x": 8.5549e-11,
197
+ "sigma_z": 0.00395442,
198
+ "sigma_delta": 0.00112542,
199
+ "T_x": 63.1134,
200
+ "T_z": 15.4736,
201
+ },
202
+ }
203
+
204
+
205
+ @pytest.mark.parametrize("emittance_coupling_factor", [0.02, 0.1, 0.5, 1.0])
206
+ def test_equilibrium_vs_elegant(emittance_coupling_factor: float, bessy3_line_with_radiation: xt.Line):
207
+ """
208
+ Load the BESSY III line and compute ierations until we reach
209
+ an equilibrium with SR and IBS, in the case where we enforce
210
+ a betatron coupling constraint on the transverse planes. The
211
+ resulting values are tested against elegant results under the
212
+ same conditions.
213
+
214
+ Note
215
+ ----
216
+ The elegant results are expected (and accepted) to be
217
+ slightly different due to small differences in the TWISS
218
+ functions, IBS growth rates etc themselves.
219
+ """
220
+ # -------------------------------------------
221
+ # Get the twiss with SR effects from the configured line
222
+ tw = bessy3_line_with_radiation.twiss(eneloss_and_damping=True)
223
+ # -------------------------------------------
224
+ # Compute the equilibrium emittances - coupling constraint
225
+ result = tw.get_ibs_and_synrad_emittance_evolution(
226
+ formalism="nagaitsev", # No Dy in the line, faster
227
+ total_beam_intensity=BUNCH_INTENSITY,
228
+ emittance_coupling_factor=emittance_coupling_factor,
229
+ emittance_constraint="coupling",
230
+ )
231
+ # -------------------------------------------
232
+ # Check Xfields results vs ELEGANT results
233
+ # Check horizontal equilibrium emittance and IBS growth rate
234
+ xo.assert_allclose(
235
+ result.eq_sr_ibs_gemitt_x,
236
+ ELEGANT_RESULTS[emittance_coupling_factor]["eps_x"],
237
+ atol=1e-12,
238
+ rtol=5e-2,
239
+ )
240
+ # Factor of 2 because different conventions between Xsuite and elegant!
241
+ xo.assert_allclose(
242
+ result.Kx[-1],
243
+ ELEGANT_RESULTS[emittance_coupling_factor]["T_x"] / 2,
244
+ rtol=6e-2,
245
+ )
246
+ # Check longitudinal equilibrium emittance and IBS growth rate
247
+ # Different eps_zeta convention between both codes
248
+ xo.assert_allclose(
249
+ result.eq_sr_ibs_gemitt_zeta,
250
+ ELEGANT_RESULTS[emittance_coupling_factor]["sigma_delta"]
251
+ * ELEGANT_RESULTS[emittance_coupling_factor]["sigma_z"],
252
+ rtol=5e-2,
253
+ )
254
+ # Factor of 2 because different conventions between Xsuite and elegant!
255
+ xo.assert_allclose(
256
+ result.Kz[-1],
257
+ ELEGANT_RESULTS[emittance_coupling_factor]["T_z"] / 2,
258
+ rtol=6e-2,
259
+ )
260
+
261
+
262
+ # ----- Some Test Functions for Behaviour ----- #
263
+
264
+
265
+ def test_missing_required_twiss_attributes_raises(bessy3_line_with_radiation: xt.Line):
266
+ """Check we raise if Twiss has no SR equilibrium values."""
267
+ tw = bessy3_line_with_radiation.twiss(eneloss_and_damping=False) # no tw.eq_*
268
+ # This should tell us we're missing something in the config
269
+ with pytest.raises(
270
+ AttributeError,
271
+ match="TwissTable must contain SR equilibrium emittances and damping constants.",
272
+ ):
273
+ tw.get_ibs_and_synrad_emittance_evolution(
274
+ formalism="Nagaitsev",
275
+ total_beam_intensity=BUNCH_INTENSITY,
276
+ emittance_coupling_factor=1,
277
+ emittance_constraint="coupling",
278
+ )
279
+
280
+
281
+ def test_missing_params_raises(bessy3_line_with_radiation: xt.Line):
282
+ """Check that not provided required params raises."""
283
+ tw = bessy3_line_with_radiation.twiss(eneloss_and_damping=True)
284
+ # These should tell us we're necessary missing arguments
285
+ with pytest.raises(AssertionError, match="Must provide 'formalism'"):
286
+ tw.get_ibs_and_synrad_emittance_evolution(
287
+ formalism=None,
288
+ total_beam_intensity=BUNCH_INTENSITY,
289
+ )
290
+ # Not providing formalism just passes to IBS rates computation which raises
291
+ with pytest.raises(TypeError):
292
+ tw.get_ibs_and_synrad_emittance_evolution(
293
+ # formalism="Nagaitsev",
294
+ total_beam_intensity=BUNCH_INTENSITY,
295
+ )
296
+ with pytest.raises(AssertionError, match="Must provide 'total_beam_intensity'"):
297
+ tw.get_ibs_and_synrad_emittance_evolution(
298
+ formalism="Nagaitsev",
299
+ total_beam_intensity=None,
300
+ )
301
+ # Not providing formalism just passes to IBS rates computation which raises
302
+ with pytest.raises(TypeError):
303
+ tw.get_ibs_and_synrad_emittance_evolution(
304
+ formalism="Nagaitsev",
305
+ # total_beam_intensity=BUNCH_INTENSITY,
306
+ )
307
+ with pytest.raises(AssertionError, match="Must provide 'rtol'"):
308
+ tw.get_ibs_and_synrad_emittance_evolution(
309
+ formalism="Nagaitsev",
310
+ total_beam_intensity=BUNCH_INTENSITY,
311
+ rtol=None,
312
+ )
313
+
314
+
315
+ @pytest.mark.parametrize("emittance_constraint", ["WRONG", "invalid"])
316
+ def test_invalid_constraint_raises(emittance_constraint, bessy3_line_with_radiation: xt.Line):
317
+ """Check we raise if the emittance coupling constraint is invalid."""
318
+ tw = bessy3_line_with_radiation.twiss(eneloss_and_damping=True)
319
+ # This should tell us we're missing something in the config
320
+ with pytest.raises(AssertionError, match="Invalid 'emittance_constraint'"):
321
+ tw.get_ibs_and_synrad_emittance_evolution(
322
+ formalism="Nagaitsev",
323
+ total_beam_intensity=BUNCH_INTENSITY,
324
+ emittance_coupling_factor=1,
325
+ emittance_constraint=emittance_constraint,
326
+ )
@@ -0,0 +1 @@
1
+ __version__ = "0.24.0"
@@ -92,17 +92,19 @@ def get_electroncloud_fieldmap_from_h5(
92
92
 
93
93
  def insert_electronclouds(eclouds, fieldmap=None, line=None):
94
94
  assert line is not None
95
+ insertions = []
96
+ env = line.env
95
97
  for name in eclouds.keys():
96
98
  s = eclouds[name]["s"]
97
99
  length = 0.
98
- line.insert_element(
99
- element=ElectronCloud(
100
+ element=ElectronCloud(
100
101
  length=length,
101
102
  fieldmap=fieldmap,
102
- _buffer=fieldmap._buffer),
103
- name=name,
104
- at_s=s)
103
+ _buffer=fieldmap._buffer)
104
+ env.elements[name] = element
105
+ insertions.append(env.place(name, at=s))
105
106
 
107
+ line.insert(insertions)
106
108
 
107
109
  def config_electronclouds(line, twiss=None, ecloud_info=None, shift_to_closed_orbit=False,
108
110
  subtract_dipolar_kicks=False, fieldmaps=None):
@@ -22,7 +22,8 @@ def install_spacecharge_frozen(line=None, _buffer=None,
22
22
  tol_spacecharge_position=None,
23
23
  s_spacecharge=None,
24
24
  delta_rms=None,
25
- z_kick_num_integ_per_sigma=0):
25
+ z_kick_num_integ_per_sigma=0,
26
+ prefix='spacecharge_'):
26
27
 
27
28
  '''
28
29
  Install spacecharge elements (frozen modeling) in a xtrack.Line object.
@@ -106,7 +107,7 @@ def install_spacecharge_frozen(line=None, _buffer=None,
106
107
  mean_y=0.,
107
108
  sigma_x=1.,
108
109
  sigma_y=1.))
109
- sc_names.append(f'spacecharge_{ii}')
110
+ sc_names.append(f'{prefix}{ii}')
110
111
 
111
112
  insertions.append((ss, [(sc_names[-1], sc_elements[-1])]))
112
113
 
@@ -5,11 +5,13 @@
5
5
 
6
6
  from ._analytical import BjorkenMtingwaIBS, IBSAmplitudeGrowthRates, IBSEmittanceGrowthRates, NagaitsevIBS
7
7
  from ._api import configure_intrabeam_scattering, get_intrabeam_scattering_growth_rates
8
+ from ._equilibrium import get_ibs_and_synrad_emittance_evolution
8
9
  from ._kicks import IBSAnalyticalKick, IBSKineticKick
9
10
 
10
11
  __all__ = [
11
12
  "BjorkenMtingwaIBS",
12
13
  "configure_intrabeam_scattering",
14
+ "get_ibs_and_synrad_emittance_evolution",
13
15
  "get_intrabeam_scattering_growth_rates",
14
16
  "IBSAmplitudeGrowthRates",
15
17
  "IBSEmittanceGrowthRates",
@@ -93,7 +93,7 @@ def get_intrabeam_scattering_growth_rates(
93
93
  # Ensure valid formalism parameter was given and determine the corresponding class
94
94
  assert formalism.lower() in ("nagaitsev", "bjorken-mtingwa", "b&m")
95
95
  if formalism.lower() == "nagaitsev":
96
- if np.count_nonzero(twiss.dy) != 0:
96
+ if not np.allclose(twiss.dy, 0, atol=1e-10): # don't complain on basically 0 vdisp
97
97
  LOGGER.warning("Vertical dispersion is present, Nagaitsev formalism does not account for it")
98
98
  ibs = NagaitsevIBS(twiss)
99
99
  else: