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.
- {xfields-0.23.2 → xfields-0.24.0}/PKG-INFO +1 -1
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_electroncloud.py +10 -3
- xfields-0.24.0/tests/test_ibs_equilibrium.py +326 -0
- xfields-0.24.0/xfields/_version.py +1 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/config_tools/electroncloud_config_tools.py +7 -5
- {xfields-0.23.2 → xfields-0.24.0}/xfields/config_tools/spacecharge_config_tools.py +3 -2
- {xfields-0.23.2 → xfields-0.24.0}/xfields/ibs/__init__.py +2 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/ibs/_api.py +1 -1
- xfields-0.24.0/xfields/ibs/_equilibrium.py +552 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields.egg-info/PKG-INFO +1 -1
- {xfields-0.23.2 → xfields-0.24.0}/xfields.egg-info/SOURCES.txt +2 -0
- xfields-0.23.2/xfields/_version.py +0 -1
- {xfields-0.23.2 → xfields-0.24.0}/LICENSE +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/MANIFEST.in +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/README.md +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/pyproject.toml +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/setup.cfg +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/setup.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_alpha_pi_setter.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_beambeam2d.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_beambeam3d_part1.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_beambeam3d_part2.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_beambeam_pic.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_beambeamstrongstrong2d.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_beambeamstrongstrong2d_pi.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_beambeamstrongstrong3d.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_beambeamstrongstrong3d_pi.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_beamstrahlung.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_beamstrahlung_pic.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_bhabha.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_cerrf.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_compressed_profile_interp_result.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_constant_charge_slicing.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_electronlens_interpolated.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_element_with_slicer_filling_scheme.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_ibs_growth_rates.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_ibs_kicks.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_iptocp_strongstrong.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_lumi.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_mean_std.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_profiles.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_slicer.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_spacecharge.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/tests/test_temp_slicer.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/__init__.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/__init__.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam2d.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam3d.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam3dpic.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam_src/beambeam.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam_src/beambeam2d.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam_src/beambeam3d.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam_src/beambeam3d_methods_for_strongstrong.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam_src/beambeam3d_ref_frame_changes.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam_src/beambeam3d_transport_sigmas.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/beambeam_src/beambeampic_methods.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/electroncloud.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/electroncloud_src/electroncloud.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/electronlens_interpolated.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/electronlens_src/electronlens_interpolated.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/element_with_slicer.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/spacecharge.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/spacecharge_src/spacecharge3d.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/spacecharge_src/spacechargebigaussian.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/temp_slicer.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/waketracker/__init__.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/waketracker/convolution.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/beam_elements/waketracker/waketracker.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/config_tools/__init__.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/config_tools/beambeam_config_tools/__init__.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/config_tools/beambeam_config_tools/_madpoint.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/config_tools/beambeam_config_tools/config_tools.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/config_tools/beambeam_config_tools/orbit_dependent_configuration_tools.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/__init__.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/bigaussian.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/bigaussian_src/bigaussian.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/bigaussian_src/bigaussian_fieldmap.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/bigaussian_src/compute_gx_gy.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/bigaussian_src/faddeeva.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/bigaussian_src/faddeeva_cernlib.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/bigaussian_src/faddeeva_mit.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/interpolated.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/interpolated_src/central_diff.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/interpolated_src/charge_deposition.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/interpolated_src/cubic_interpolators.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/interpolated_src/linear_interpolators.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/interpolated_src/tricubic_coefficients.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/fieldmaps/tricubicinterpolated.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/general.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/headers/beamstrahlung_spectrum.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/headers/beamstrahlung_spectrum_pic.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/headers/bhabha_spectrum.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/headers/compressed_profile.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/headers/compute_slice_moments.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/headers/constants.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/headers/particle_states.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/headers/power_n.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/headers/sincos.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/ibs/_analytical.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/ibs/_formulary.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/ibs/_kicks.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/longitudinal_profiles/__init__.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/longitudinal_profiles/coasting.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/longitudinal_profiles/qgaussian.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/longitudinal_profiles/qgaussian_src/qgaussian.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/slicers/__init__.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/slicers/compressed_profile.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/slicers/slicers_src/uniform_bin_slicer.h +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/slicers/uniform.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/solvers/__init__.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/solvers/base.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/solvers/fftsolvers.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/test_support/__init__.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields/test_support/temp_makepart.py +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields.egg-info/dependency_links.txt +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields.egg-info/requires.txt +0 -0
- {xfields-0.23.2 → xfields-0.24.0}/xfields.egg-info/top_level.txt +0 -0
|
@@ -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,
|
|
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
|
-
|
|
99
|
-
element=ElectronCloud(
|
|
100
|
+
element=ElectronCloud(
|
|
100
101
|
length=length,
|
|
101
102
|
fieldmap=fieldmap,
|
|
102
|
-
_buffer=fieldmap._buffer)
|
|
103
|
-
|
|
104
|
-
|
|
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'
|
|
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.
|
|
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:
|