xcoll 0.6.0__py3-none-any.whl → 0.6.1__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.

Potentially problematic release.


This version of xcoll might be problematic. Click here for more details.

xcoll/__init__.py.orig ADDED
@@ -0,0 +1,26 @@
1
+ # copyright ############################### #
2
+ # This file is part of the Xcoll package. #
3
+ # Copyright (c) CERN, 2025. #
4
+ # ######################################### #
5
+
6
+ from .general import _pkg_root, __version__, citation
7
+
8
+ <<<<<<< HEAD
9
+ from .beam_elements import BlackAbsorber, BlackCrystal, EverestBlock, EverestCollimator, EverestCrystal, \
10
+ Geant4Collimator, BlowUp, EmittanceMonitor, collimator_classes, crystal_classes, element_classes
11
+ =======
12
+ from .beam_elements import BlackAbsorber, BlackCrystal, TransparentCollimator, TransparentCrystal, \
13
+ EverestBlock, EverestCollimator, EverestCrystal, BlowUp, EmittanceMonitor, \
14
+ collimator_classes, crystal_classes, element_classes
15
+ >>>>>>> main
16
+ from .scattering_routines.everest import materials, Material, CrystalMaterial
17
+ from .scattering_routines.geant4 import Geant4Engine
18
+ from .colldb import CollimatorDatabase
19
+ from .interaction_record import InteractionRecord
20
+ from .rf_sweep import RFSweep
21
+ from .lossmap import LossMap, MultiLossMap
22
+
23
+
24
+ # print("If you use Xcoll in your simulations, please cite us :-)")
25
+ # print(citation)
26
+
xcoll/general.py CHANGED
@@ -12,5 +12,5 @@ citation = "F.F. Van der Veken, et al.: Recent Developments with the New Tools f
12
12
  # ======================
13
13
  # Do not change
14
14
  # ======================
15
- __version__ = '0.6.0'
15
+ __version__ = '0.6.1'
16
16
  # ======================
xcoll/general.py.orig ADDED
@@ -0,0 +1,20 @@
1
+ # copyright ############################### #
2
+ # This file is part of the Xcoll package. #
3
+ # Copyright (c) CERN, 2024. #
4
+ # ######################################### #
5
+
6
+ from pathlib import Path
7
+
8
+ _pkg_root = Path(__file__).parent.absolute()
9
+
10
+ citation = "F.F. Van der Veken, et al.: Recent Developments with the New Tools for Collimation Simulations in Xsuite, Proceedings of HB2023, Geneva, Switzerland."
11
+
12
+ # ======================
13
+ # Do not change
14
+ # ======================
15
+ <<<<<<< HEAD
16
+ __version__ = '0.5.11.dev0+geant4'
17
+ =======
18
+ __version__ = '0.6.0'
19
+ >>>>>>> main
20
+ # ======================
@@ -0,0 +1,256 @@
1
+ # copyright ############################### #
2
+ # This file is part of the Xcoll package. #
3
+ # Copyright (c) CERN, 2025. #
4
+ # ######################################### #
5
+
6
+ import numpy as np
7
+ from warnings import warn
8
+
9
+ import xtrack as xt
10
+ import xobjects as xo
11
+ import xpart as xp
12
+
13
+ <<<<<<< HEAD
14
+ from .beam_elements import collimator_classes, EverestCrystal, Geant4Collimator
15
+ =======
16
+ from .beam_elements import collimator_classes, BaseCrystal
17
+ >>>>>>> main
18
+
19
+
20
+ def generate_pencil_on_collimator(line, name, num_particles, *, side='+-', pencil_spread=1e-6,
21
+ impact_parameter=0, sigma_z=7.61e-2, twiss=None, longitudinal=None,
22
+ longitudinal_betatron_cut=None, _capacity=None, tw=None,
23
+ _longitudinal_coords=None, **kwargs):
24
+ """Generate a pencil beam on a collimator."""
25
+
26
+ # Do some general checks
27
+ if not line._has_valid_tracker():
28
+ raise ValueError("Please build tracker before generating pencil distribution!")
29
+ coll = line[name]
30
+ if not isinstance(coll, tuple(collimator_classes)):
31
+ raise ValueError("Need to provide a valid collimator!")
32
+ if coll.optics is None:
33
+ raise ValueError("Need to assign optics to collimators before generating pencil distribution!")
34
+ num_particles = int(num_particles)
35
+ if len(line.get_elements_of_type(Geant4Collimator)[0]) > 0:
36
+ kwargs.setdefault('_capacity', 2*num_particles)
37
+
38
+ # Define the plane
39
+ angle = coll.angle
40
+ if abs(np.mod(angle-90,180)-90) < 1e-6:
41
+ plane = 'x'
42
+ transv_plane = 'y'
43
+ elif abs(np.mod(angle,180)-90) < 1e-6:
44
+ plane = 'y'
45
+ transv_plane = 'x'
46
+ else:
47
+ raise NotImplementedError("Pencil beam on a skew collimator not yet supported!")
48
+
49
+ if coll.side == 'left':
50
+ if side == '-':
51
+ raise ValueError("Cannot generate a pencil on the right jaw of a left-"
52
+ "sided collimator!")
53
+ side = '+'
54
+ if coll.side == 'right':
55
+ if side == '+':
56
+ raise ValueError("Cannot generate a pencil on the left jaw of a right-"
57
+ "sided collimator!")
58
+ side = '-'
59
+
60
+ if tw is not None:
61
+ warn("The argument tw is deprecated. Please use twiss instead.", FutureWarning)
62
+ if twiss is None:
63
+ twiss = tw
64
+
65
+ if twiss is None:
66
+ twiss = line.twiss()
67
+
68
+ # Longitudinal plane
69
+ if _longitudinal_coords:
70
+ zeta = _longitudinal_coords[0]
71
+ delta = _longitudinal_coords[1]
72
+
73
+ else:
74
+ zeta, delta = _generate_longitudinal_dist(line, num_particles, sigma_z, longitudinal)
75
+
76
+ # Generate 4D coordinates
77
+ # TODO: there is some looping in the calculation here and in xpart. Can it be improved?
78
+ if side == '+-':
79
+ num_plus = int(num_particles/2)
80
+ num_min = int(num_particles - num_plus)
81
+ zeta_plus = zeta[:num_plus] if hasattr(zeta, '__iter__') else zeta
82
+ zeta_min = zeta[num_plus:] if hasattr(zeta, '__iter__') else zeta
83
+ delta_plus = delta[:num_plus] if hasattr(delta, '__iter__') else delta
84
+ delta_min = delta[num_plus:] if hasattr(delta, '__iter__') else delta
85
+ if _capacity:
86
+ _capacity_plus = int(_capacity/2)
87
+ _capacity_min = int(_capacity - _capacity_plus)
88
+ else:
89
+ _capacity_plus = None
90
+ _capacity_min = None
91
+ part_plus = generate_pencil_on_collimator(line=line, name=name, num_particles=num_plus,
92
+ impact_parameter=impact_parameter, _capacity=_capacity_plus,
93
+ side='+', pencil_spread=pencil_spread, twiss=twiss,
94
+ _longitudinal_coords=[zeta_plus, delta_plus],
95
+ **kwargs)
96
+ part_min = generate_pencil_on_collimator(line=line, name=name, num_particles=num_min,
97
+ impact_parameter=impact_parameter, _capacity=_capacity_min,
98
+ side='-', pencil_spread=pencil_spread, twiss=twiss,
99
+ _longitudinal_coords=[zeta_min, delta_min],
100
+ **kwargs)
101
+
102
+ part = xt.Particles.merge([part_plus, part_min])
103
+ part.start_tracking_at_element = part_plus.start_tracking_at_element
104
+ assert part.start_tracking_at_element == part_min.start_tracking_at_element
105
+ return part
106
+
107
+ pencil, p_pencil, transverse_norm, p_transverse_norm, is_converging, at_element = \
108
+ _generate_4D_pencil_one_jaw(line, name, num_particles, plane, side,
109
+ impact_parameter, pencil_spread, twiss, **kwargs)
110
+
111
+ # Build the particles
112
+ if plane == 'x':
113
+ part = xp.build_particles(
114
+ x=pencil, px=p_pencil, y_norm=transverse_norm, py_norm=p_transverse_norm,
115
+ zeta=zeta, delta=delta, nemitt_x=coll.nemitt_x, nemitt_y=coll.nemitt_y,
116
+ line=line, at_element=at_element, _context=coll._buffer.context, **kwargs
117
+ )
118
+ else:
119
+ part = xp.build_particles(
120
+ x_norm=transverse_norm, px_norm=p_transverse_norm, y=pencil, py=p_pencil,
121
+ zeta=zeta, delta=delta, nemitt_x=coll.nemitt_x, nemitt_y=coll.nemitt_y,
122
+ line=line, at_element=at_element, _context=coll._buffer.context, **kwargs
123
+ )
124
+
125
+ part._init_random_number_generator()
126
+
127
+ if not is_converging:
128
+ dri = xt.Drift(length=-coll.length)
129
+ dri.track(part)
130
+ part.start_tracking_at_element -= 1
131
+ part.at_element -= 1
132
+
133
+ return part
134
+
135
+
136
+ def generate_delta_from_dispersion(line, at_element, *, plane, position_mm, nemitt_x, nemitt_y,
137
+ twiss=None, betatron_cut=0, match_at_front=True):
138
+ if line.tracker is None:
139
+ raise ValueError("Need to build tracker first!")
140
+ if not hasattr(betatron_cut, '__iter__'):
141
+ if hasattr(position_mm, '__iter__'):
142
+ betatron_cut = np.full_like(position_mm, betatron_cut)
143
+ elif not hasattr(position_mm, '__iter__'):
144
+ position_mm = np.full_like(betatron_cut, position_mm)
145
+ elif len(position_mm) != len(betatron_cut):
146
+ raise ValueError
147
+ if plane not in ['x', 'y']:
148
+ raise ValueError("The variable 'plane' needs to be either 'x' or 'y'!")
149
+
150
+ if twiss is None:
151
+ twiss = line.twiss()
152
+
153
+ beam_sizes = twiss.get_beam_covariance(nemitt_x=nemitt_x, nemitt_y=nemitt_y)
154
+ beam_sizes = beam_sizes.rows[at_element:f'{at_element}>>1'][f'sigma_{plane}']
155
+ sigma = beam_sizes[0] if match_at_front else beam_sizes[1]
156
+ delta = (position_mm - betatron_cut*sigma - twiss.rows[at_element][plane])
157
+ delta /= twiss.rows[at_element][f'd{plane}']
158
+
159
+ return delta
160
+
161
+
162
+ def _generate_4D_pencil_one_jaw(line, name, num_particles, plane, side, impact_parameter,
163
+ pencil_spread, twiss=None, _capacity=None, **kwargs):
164
+ coll = line[name]
165
+ beam_sizes = twiss.get_beam_covariance(nemitt_x=coll.nemitt_x, nemitt_y=coll.nemitt_y)
166
+
167
+ # Is it converging or diverging?
168
+ # TODO: dispersion might change this
169
+ # TODO: skew collimators
170
+ tolerance_tilt = 1e-12 # 0.1 urad tolerance on jaw tilt => we prioritise converging
171
+ divergence = coll.divergence
172
+ if side == '+':
173
+ if isinstance(coll, BaseCrystal):
174
+ # A pencil on the crystal should always be upstream
175
+ is_converging = True
176
+ pencil_pos = coll.jaw_U + impact_parameter
177
+ else:
178
+ betatron_angle = coll.gap_L * divergence
179
+ is_converging = coll.tilt_L + tolerance_tilt >= betatron_angle
180
+ print(f"Left jaw of collimator {name} is {'con' if is_converging else 'di'}verging.")
181
+ if is_converging:
182
+ pencil_pos = coll.jaw_LU + impact_parameter
183
+ else:
184
+ pencil_pos = coll.jaw_LD + impact_parameter
185
+ elif side == '-':
186
+ if isinstance(coll, BaseCrystal):
187
+ # A pencil on the crystal should always be upstream
188
+ is_converging = True
189
+ pencil_pos = coll.jaw_U - impact_parameter
190
+ else:
191
+ betatron_angle = coll.gap_R * divergence
192
+ is_converging = coll.tilt_R - tolerance_tilt <= betatron_angle
193
+ print(f"Right jaw of collimator {name} is {'con' if is_converging else 'di'}verging.")
194
+ if is_converging:
195
+ pencil_pos = coll.jaw_RU - impact_parameter
196
+ else:
197
+ pencil_pos = coll.jaw_RD - impact_parameter
198
+ else:
199
+ raise ValueError(f"Sinde {side} not supported in _generate_4D_pencil_one_jaw!")
200
+
201
+ if is_converging:
202
+ # pencil at front of jaw
203
+ sigma = beam_sizes.rows[name:f'{name}>>1'][f'sigma_{plane}'][0]
204
+ tw_at_s = twiss.rows[name]
205
+ at_element = name
206
+ else:
207
+ # pencil at back of jaw
208
+ sigma = beam_sizes.rows[name:f'{name}>>1'][f'sigma_{plane}'][1]
209
+ tw_at_s = twiss.rows[f'{name}>>1']
210
+ at_element = line.element_names[line.element_names.index(name)+1]
211
+
212
+ dr_sigmas = pencil_spread/sigma
213
+
214
+ # Collimator plane: generate pencil distribution
215
+ pencil, p_pencil = xp.generate_2D_pencil_with_absolute_cut(
216
+ num_particles, plane=plane, absolute_cut=pencil_pos, line=line,
217
+ dr_sigmas=dr_sigmas, nemitt_x=coll.nemitt_x, nemitt_y=coll.nemitt_y,
218
+ at_element=at_element, side=side, twiss=tw_at_s, **kwargs
219
+ )
220
+
221
+ # Other plane: generate gaussian distribution in normalized coordinates
222
+ transverse_norm = np.random.normal(size=num_particles)
223
+ p_transverse_norm = np.random.normal(size=num_particles)
224
+
225
+ return pencil, p_pencil, transverse_norm, p_transverse_norm, is_converging, at_element
226
+
227
+
228
+ def _generate_longitudinal_dist(line, num_particles, sigma_z, longitudinal):
229
+ # TODO: make this more general, make this better
230
+ if longitudinal is None:
231
+ return 0, 0
232
+ elif longitudinal == 'matched_dispersion':
233
+ raise NotImplementedError
234
+ # if longitudinal_betatron_cut is None:
235
+ # cut = 0
236
+ # else:
237
+ # cut = np.random.uniform(-longitudinal_betatron_cut, longitudinal_betatron_cut,
238
+ # num_particles)
239
+ # delta = generate_delta_from_dispersion(line, name, plane=plane, position_mm=pencil,
240
+ # nemitt_x=nemitt_x, nemitt_y=nemitt_y, twiss=tw,
241
+ # betatron_cut=cut, match_at_front=is_converging)
242
+ # zeta = 0
243
+ elif longitudinal == 'bucket':
244
+ return xp.generate_longitudinal_coordinates(
245
+ num_particles=num_particles, distribution='gaussian', sigma_z=sigma_z, line=line
246
+ )
247
+ elif not hasattr(longitudinal, '__iter__'):
248
+ raise ValueError
249
+ elif len(longitudinal) != 2:
250
+ raise ValueError
251
+ elif isinstance(longitudinal, str):
252
+ raise ValueError
253
+ elif isinstance(longitudinal, dict):
254
+ return longitudinal['zeta'], longitudinal['delta']
255
+ else:
256
+ return longitudinal[0], longitudinal[1]
xcoll/plot.py CHANGED
@@ -5,7 +5,6 @@
5
5
 
6
6
  import numpy as np
7
7
  from numbers import Number
8
- import matplotlib.pyplot as plt
9
8
 
10
9
 
11
10
  _NORMS = ["total", "coll_max", "max", "none", "raw"]
@@ -13,6 +12,7 @@ _NORMS = ["total", "coll_max", "max", "none", "raw"]
13
12
 
14
13
  def _plot_lossmap_base(lossmap: dict, *, norm="total", ax=None, xlim=None, ylim=None,
15
14
  legend=True, grid=True, energy=False, show=True, savefig=None):
15
+ import matplotlib.pyplot as plt
16
16
  if norm in _NORMS:
17
17
  norm = norm.lower()
18
18
  elif not isinstance(norm, Number):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xcoll
3
- Version: 0.6.0
3
+ Version: 0.6.1
4
4
  Summary: Xsuite collimation package
5
5
  Home-page: https://github.com/xsuite/xcoll
6
6
  License: Apache 2.0
@@ -21,7 +21,7 @@ Requires-Dist: ruamel-yaml (>=0.17.31,<0.18.0) ; extra == "tests"
21
21
  Requires-Dist: xdeps (>=0.10.5)
22
22
  Requires-Dist: xobjects (>=0.5.0)
23
23
  Requires-Dist: xpart (>=0.23.0)
24
- Requires-Dist: xtrack (>=0.84.5)
24
+ Requires-Dist: xtrack (>=0.84.6)
25
25
  Project-URL: Repository, https://github.com/xsuite/xcoll
26
26
  Description-Content-Type: text/markdown
27
27
 
@@ -1,6 +1,7 @@
1
1
  LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
2
2
  NOTICE,sha256=6DO_E7WCdRKc42vUoVVBPGttvQi4mRt9fAcxj9u8zy8,74
3
3
  xcoll/__init__.py,sha256=wEk3szUGeeN2Bg7_nx2D2pCgzRR0zcbEcWCP33p-e3I,854
4
+ xcoll/__init__.py.orig,sha256=h9YXS-ZlmC-ZWLoLoAe8V175f2xc6E9gfoe_VjRYwBw,1172
4
5
  xcoll/beam_elements/__init__.py,sha256=qu2-LefWfEKZHfALGqZo97DTrwdZVh7Sp97V-3XokJU,1189
5
6
  xcoll/beam_elements/absorber.py,sha256=Gw1l1ng1MqF0dRTk7YhkiPAoinS5xsTASMxMDWGsmTw,2842
6
7
  xcoll/beam_elements/base.py,sha256=mjnzLbZ-GC56N56Eq5r5oQB8cLmeaqR5oEH1-FnS_H4,57816
@@ -18,17 +19,19 @@ xcoll/beam_elements/everest.py,sha256=iJva_S0OQnmG-qj7rIAiUCssu5WL_Qs5P_n6Qx-IWz
18
19
  xcoll/beam_elements/monitor.py,sha256=baMYT_PNya8KX35ReeMwk5Cm04ePUqiDF_s69L5GTX0,16968
19
20
  xcoll/beam_elements/transparent.py,sha256=AZOWfH3dvsetL6DjQGejUgX7T18e_3omIIffG_1gwc0,2894
20
21
  xcoll/colldb.py,sha256=WaJC6gkDNVvxo65OhucTM6Fwo6pgRFHNnBnHSkiX7AQ,31054
21
- xcoll/general.py,sha256=kSLikai9J-AWrL9oj9LXhvIKN6bMW7-RpWd4LZCH5A0,534
22
+ xcoll/general.py,sha256=mXL1LaNUxbgXm4AthRJ_7j5oA48cgPDtksQwYmPzLXY,534
23
+ xcoll/general.py.orig,sha256=AvtA-RygKcKCRLDkldzzwG7Q7GlBI49df3aNWe-rr_Y,603
22
24
  xcoll/headers/checks.h,sha256=qdXsOTBOK1MwW6bdFF93j4yE648mcDtEv5rGN1w9sfk,1582
23
25
  xcoll/headers/particle_states.py,sha256=N8ehLtg99358I4RGCJ3sjuKCk2LVdGqgVx2xGoHrRdM,1959
24
26
  xcoll/initial_distribution.py,sha256=CHhqeCVjVOyaBWhfy2sDgLwIgtXZoqcTW-su-M2YByE,10989
27
+ xcoll/initial_distribution.py.orig,sha256=PRZwBtQ2qY_2g6f879IEhUxmNu1tpTArt-qKYNqpjSI,11223
25
28
  xcoll/interaction_record/__init__.py,sha256=UFoLiKa-z2oX7YoszP-7Vgdt1nM6kT382v1CaIu8_u0,50
26
29
  xcoll/interaction_record/interaction_record.py,sha256=cCjfVCYUJaV0Y-pCljA2_u8GLyhHt7zNjbSXkE7cRO4,13299
27
30
  xcoll/interaction_record/interaction_record_src/interaction_record.h,sha256=0rNagnfSGc2i1jauOMIcDbj9QFic9dV_MOyqVx1kw5Q,6067
28
31
  xcoll/interaction_record/interaction_types.py,sha256=XTeg2dcImMpqhTqzkJKh6JYam2v9gUMhED-dDKLsilk,2894
29
32
  xcoll/line_tools.py,sha256=JBySkKKZ-RGumqAZF_8PSQ3OV0M87P78NeQgbXAdFc4,16699
30
33
  xcoll/lossmap.py,sha256=HLdhej9tUjk36T5BulVWurJtfiNa61L_1X7-8kT6JoQ,28407
31
- xcoll/plot.py,sha256=uy19w0aLufYKpk6RuL265Y8Skl4NgzEuJFF8ur0ezYw,4067
34
+ xcoll/plot.py,sha256=27fYdXstPg3o8XyeBlPuD2yz0GR3dKkNWy4kO2BD9WA,4071
32
35
  xcoll/rf_sweep.py,sha256=hMgW15uTp7qPprdlHCZBjOOe8Emdm-R0TfxPDoRXnJU,9021
33
36
  xcoll/scattering_routines/engine.py,sha256=1VCBEZLMd5orFo3sZqK51NrqbqELBVrbsz6bB2SXsFQ,22962
34
37
  xcoll/scattering_routines/environment.py,sha256=xZ8A7XfvSfpe8vYbM5oD5qbcp8Tuag5qWAI6VqgGUlA,12033
@@ -128,8 +131,8 @@ xcoll/scattering_routines/geometry/rotation.h,sha256=lO3RaQBys9r0ROMjR8T8Rr7UsIE
128
131
  xcoll/scattering_routines/geometry/segments.h,sha256=7nKnnin2ByxkKyaYwGvFaqgLQg5uBba4CdLHL7L3iQs,7667
129
132
  xcoll/scattering_routines/geometry/sort.h,sha256=b1MkFO2ddzv1fWGeQzsLuz46qo2pKyRSXHjoAEVU7Ts,5763
130
133
  xcoll/xaux.py,sha256=mh4E_jhaUFm2LOKawJ0b6X4zuz8JiJhx6w7GcnRgIXQ,2291
131
- xcoll-0.6.0.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
132
- xcoll-0.6.0.dist-info/METADATA,sha256=pvIhoCK7JIHzHWv-Alykk78jooTeySkRYg0cAofiHtk,2676
133
- xcoll-0.6.0.dist-info/NOTICE,sha256=6DO_E7WCdRKc42vUoVVBPGttvQi4mRt9fAcxj9u8zy8,74
134
- xcoll-0.6.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
135
- xcoll-0.6.0.dist-info/RECORD,,
134
+ xcoll-0.6.1.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
135
+ xcoll-0.6.1.dist-info/METADATA,sha256=qZ6WjBbpMtmyC5jeyM39MTNXw779decuHpGDHOShgpY,2676
136
+ xcoll-0.6.1.dist-info/NOTICE,sha256=6DO_E7WCdRKc42vUoVVBPGttvQi4mRt9fAcxj9u8zy8,74
137
+ xcoll-0.6.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
138
+ xcoll-0.6.1.dist-info/RECORD,,
File without changes
File without changes
File without changes