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

@@ -20,15 +20,13 @@ crystal_classes = tuple(v for v in globals().values()
20
20
  if isinstance(v, type) and issubclass(v, BaseCrystal) and v != BaseCrystal)
21
21
 
22
22
  element_classes = block_classes + (BlowUp, EmittanceMonitor)
23
-
24
23
  <<<<<<< HEAD
24
+
25
25
  # These should not go into any of the classes lists
26
+ # but are added for compatibility with _K2
26
27
  from .k2 import _K2Collimator, _K2Crystal
28
+ _all_block_classes = block_classes + (_K2Collimator, _K2Crystal)
27
29
  _all_collimator_classes = collimator_classes + (_K2Collimator, _K2Crystal)
28
30
  _all_crystal_classes = crystal_classes + (_K2Crystal,)
29
31
  =======
30
- # For compatibility with _K2Collimators
31
- _all_block_classes = block_classes
32
- _all_collimator_classes = collimator_classes
33
- _all_crystal_classes = crystal_classes
34
32
  >>>>>>> release/v0.6.0
@@ -138,6 +138,7 @@ EverestCollData EverestCrystal_init(EverestCrystalData el, LocalParticle* part0,
138
138
  coll->csref[0] = CrystalMaterialData_get_cross_section(material, 0);
139
139
  coll->csref[1] = CrystalMaterialData_get_cross_section(material, 1);
140
140
  coll->csref[5] = CrystalMaterialData_get_cross_section(material, 5);
141
+ coll->only_mcs = CrystalMaterialData_get__only_mcs(material);
141
142
  coll->dlri = CrystalMaterialData_get_crystal_radiation_length(material);
142
143
  coll->dlyi = CrystalMaterialData_get_crystal_nuclear_length(material);
143
144
  coll->ai = CrystalMaterialData_get_crystal_plane_distance(material);
xcoll/colldb.py.orig ADDED
@@ -0,0 +1,654 @@
1
+ # copyright ############################### #
2
+ # This file is part of the Xcoll package. #
3
+ # Copyright (c) CERN, 2024. #
4
+ # ######################################### #
5
+
6
+ import io
7
+ import re
8
+ import json
9
+ import numpy as np
10
+ import pandas as pd
11
+ from pathlib import Path
12
+
13
+ import xtrack as xt
14
+
15
+ from .beam_elements import BlackAbsorber, BlackCrystal, EverestCollimator, EverestCrystal, \
16
+ <<<<<<< HEAD
17
+ FlukaCollimator, BaseCollimator, BaseCrystal, _all_collimator_classes
18
+ =======
19
+ BaseCollimator, BaseCrystal, collimator_classes
20
+ >>>>>>> release/v0.6.0
21
+ from .scattering_routines.everest.materials import SixTrack_to_xcoll
22
+ from .scattering_routines.fluka import FlukaEngine
23
+
24
+
25
+ def _initialise_None(dct):
26
+ fields = {'gap': None, 'angle': 0, 'offset': 0, 'parking': 1, 'jaw': None, 'family': None}
27
+ fields.update({'overwritten_keys': [], 'side': 'both', 'material': None, 'stage': None})
28
+ fields.update({'length': 0, 'collimator_type': None, 'active': True, 'crystal': None, 'tilt': 0})
29
+ fields.update({'bending_radius': None, 'bending_angle': None, 'width': 0, 'height': 0, 'miscut': 0})
30
+ for f, val in fields.items():
31
+ if f not in dct.keys():
32
+ dct[f] = val
33
+ for key in dct.keys():
34
+ if key not in fields.keys():
35
+ raise ValueError(f"Illegal setting {key} in collimator!")
36
+
37
+
38
+ def _dict_keys_to_lower(dct):
39
+ if isinstance(dct, dict):
40
+ return {k.lower(): _dict_keys_to_lower(v) for k,v in dct.items()}
41
+ else:
42
+ return dct
43
+
44
+
45
+ def _get_coll_dct_by_beam(coll, beam):
46
+ # The dictionary can be a CollimatorDatabase for a single beam (beam=None)
47
+ # or for both beams (beam='b1' or beam='b2)
48
+ if beam is not None:
49
+ if isinstance(beam, int) or len(beam) == 1:
50
+ beam = f'b{beam}'
51
+ beam = beam.lower()
52
+ beam_in_db = list(coll.keys())
53
+
54
+ if beam_in_db == ['b1','b2']:
55
+ if beam is None:
56
+ raise ValueError("Need to specify a beam, because the given dict is for both beams!")
57
+ return coll[beam]
58
+
59
+ elif len(beam_in_db) == 1:
60
+ if beam is None:
61
+ beam = beam_in_db[0].lower()
62
+ elif beam != beam_in_db[0].lower():
63
+ raise ValueError("Variable 'beam' does not match beam specified in CollimatorDatabase!")
64
+ return coll[beam]
65
+
66
+ elif beam is not None:
67
+ print("Warning: Specified a beam, but the CollimatorDatabase is for a single beam only!")
68
+ return coll
69
+
70
+
71
+ class CollimatorDatabase:
72
+
73
+ def __init__(self, **kwargs):
74
+ # Get all arguments
75
+ for key in ['collimator_dict', 'nemitt_x', 'nemitt_y']:
76
+ if key not in kwargs.keys():
77
+ raise ValueError(f"CollimatorDatabase is missing required argument '{key}'!")
78
+
79
+ self._parse_dict(kwargs['collimator_dict'],
80
+ kwargs.get('family_dict', {}),
81
+ kwargs.get('beam', None),
82
+ kwargs.get('_yaml_merged', False),
83
+ kwargs.get('ignore_crystals', True))
84
+ self.nemitt_x = kwargs['nemitt_x']
85
+ self.nemitt_y = kwargs['nemitt_y']
86
+ self._elements = {}
87
+
88
+
89
+ def _parse_dict(self, coll, fam, beam=None, _yaml_merged=False, ignore_crystals=True):
90
+ # We make all keys case-insensitive to avoid confusion between different conventions
91
+ coll = _dict_keys_to_lower(coll)
92
+ fam = _dict_keys_to_lower(fam)
93
+
94
+ # The dictionary can be a CollimatorDatabase for a single beam (beam=None)
95
+ # or for both beams (beam='b1' or beam='b2)
96
+ coll = _get_coll_dct_by_beam(coll, beam)
97
+
98
+ # Apply family settings
99
+ crystals = []
100
+ for thiscoll, settings in coll.items():
101
+ settings = {k.lower(): v for k,v in settings.items()}
102
+ if 'family' in settings.keys() and settings['family'] is not None:
103
+ settings['family'] = settings['family'].lower()
104
+ thisfam = settings['family']
105
+ if thisfam not in fam.keys():
106
+ raise ValueError(f"Collimator {thiscoll} depends on family {thisfam}, "
107
+ + f"but the latter is not defined!")
108
+
109
+ # Check if some family settings are overwritten for this collimator
110
+ # Only do this check if we didn't do a YAML merge earlier (because then it
111
+ # is already taken care of)
112
+ if not _yaml_merged:
113
+ overwritten_keys = [key.lower() for key in settings.keys() if key in fam[thisfam]]
114
+ if len(overwritten_keys) > 0:
115
+ settings['overwritten_keys'] = overwritten_keys
116
+
117
+ # Load family settings, potentially overwriting settings for this collimator
118
+ settings = {**fam[thisfam], **settings}
119
+
120
+ else:
121
+ settings['family'] = None
122
+ coll[thiscoll] = settings
123
+
124
+ # Save list of crystals
125
+ if 'crystal' in settings:
126
+ if settings['crystal'] != 0.0:
127
+ crystals += [thiscoll]
128
+ else:
129
+ settings['crystal'] = None
130
+
131
+ # Remove crystals from colldb
132
+ if ignore_crystals:
133
+ for thiscoll in crystals:
134
+ del coll[thiscoll]
135
+
136
+ # Check that all collimators have gap settings
137
+ if not np.all(['gap' in val.keys() or 'jaw' in val.keys() for val in coll.values()]):
138
+ raise ValueError("Ill-defined CollimatorDatabase: Not all collimators have a gap or "
139
+ + "jaw setting, (or the keys / structure of the dictionary is wrong)!")
140
+
141
+ # Update collimators with default values for missing keys
142
+ for name, collimator in coll.items():
143
+ # Change all values to lower case
144
+ for key, val in collimator.items():
145
+ collimator[key] = val.lower() if isinstance(val, str) else val
146
+ _initialise_None(collimator)
147
+
148
+ self._collimator_dict = coll
149
+ self._family_dict = fam
150
+
151
+ # =======================================
152
+ # ====== Loading/dumping functions ======
153
+ # =======================================
154
+
155
+ @classmethod
156
+ def from_yaml(cls, file, **kwargs):
157
+ # Only do the import here, as to not force people to install
158
+ # ruamel if they don't load CollimatorDatabase yaml's
159
+ from ruamel.yaml import YAML
160
+ yaml = YAML(typ='safe')
161
+ if isinstance(file, io.IOBase):
162
+ dct = yaml.load(file)
163
+ else:
164
+ file = Path(file).resolve()
165
+ with file.open('r') as fid:
166
+ dct = yaml.load(fid)
167
+ dct = _dict_keys_to_lower(dct)
168
+
169
+ # If the CollimatorDatabase uses YAML merging, we need a bit of hackery to get the
170
+ # family names from the tags (anchors/aliases)
171
+ _yaml_merged = False
172
+ if 'families' in dct.keys() and not isinstance(dct['families'], dict):
173
+ _yaml_merged = True
174
+
175
+ # First we load a round-trip yaml
176
+ yaml = YAML()
177
+ if isinstance(file, io.IOBase):
178
+ full_dct = yaml.load(file)
179
+ else:
180
+ with open(file, 'r') as fid:
181
+ full_dct = yaml.load(fid)
182
+ famkey = [key for key in full_dct.keys() if key.lower() == 'families'][0]
183
+ collkey = [key for key in full_dct.keys() if key.lower() == 'collimators'][0]
184
+ families = {}
185
+
186
+ # We loop over family names to get the name tag ('anchor') of each family
187
+ for fam, full_fam in zip(dct['families'], full_dct[famkey]):
188
+ if full_fam.anchor.value is None:
189
+ raise ValueError("Missing name tag / anchor in "
190
+ + "CollimatorDatabase['families']!")
191
+ # We get the anchor from the rt yaml, and use it as key in the families dict
192
+ families[full_fam.anchor.value.lower()] = {f.lower(): v for f, v in fam.items()}
193
+ dct['families'] = families
194
+
195
+ # Now we need to loop over each collimator, and verify which family was used
196
+ beam = kwargs.get('beam', None)
197
+ coll_dct = _get_coll_dct_by_beam(dct['collimators'], beam)
198
+ full_coll_dct = _get_coll_dct_by_beam(full_dct[collkey], beam)
199
+ for coll, full_coll in zip(coll_dct.values(), full_coll_dct.values()):
200
+ if not isinstance(coll['gap'], (int,float)):
201
+ coll['gap'] = None
202
+ if 'family' in coll.keys():
203
+ raise ValueError(f"Error in {coll}: Cannot use merging for families "
204
+ + "and manually specify family as well!")
205
+ elif len(full_coll.merge) > 0:
206
+ coll['family'] = full_coll.merge[0][1].anchor.value.lower()
207
+ # Check if some family settings are overwritten for this collimator
208
+ overwritten_keys = [key.lower() for key in full_coll.keys()
209
+ if full_coll._unmerged_contains(key)
210
+ and key.lower() in families[coll['family']].keys()]
211
+ if len(overwritten_keys) > 0:
212
+ coll['overwritten_keys'] = overwritten_keys
213
+ else:
214
+ coll['family'] = None
215
+
216
+ return cls.from_dict(dct, _yaml_merged=_yaml_merged, **kwargs)
217
+
218
+
219
+ @classmethod
220
+ def from_json(cls, file, **kwargs):
221
+ if isinstance(file, io.IOBase):
222
+ dct = json.load(file)
223
+ else:
224
+ file = Path(file).resolve()
225
+ with file.open('r') as fid:
226
+ dct = json.load(fid)
227
+ dct = _dict_keys_to_lower(dct)
228
+ return cls.from_dict(dct, **kwargs)
229
+
230
+
231
+ @classmethod
232
+ def from_dict(cls, dct, beam=None, _yaml_merged=False, nemitt_x=None, nemitt_y=None, ignore_crystals=True):
233
+ # We make all keys case-insensitive to avoid confusion between different conventions
234
+ # The families are optional
235
+ fam = {}
236
+ dct = _dict_keys_to_lower(dct)
237
+
238
+ # Get the emittance
239
+ if nemitt_x is None and nemitt_y is None:
240
+ if 'emittance' not in dct.keys():
241
+ raise ValueError("Missing emittance info! Add 'emittance' as a key to "
242
+ + "the CollimatorDatabase file, or specify it as 'nemitt_x' "
243
+ + "and 'nemitt_y' to the loader!")
244
+ nemitt_x = dct['emittance']['x']
245
+ nemitt_y = dct['emittance']['y']
246
+ elif nemitt_x is None or nemitt_y is None:
247
+ raise ValueError("Need to provide both 'nemitt_x' and 'nemitt_y'!")
248
+ elif 'emittance' in dct.keys():
249
+ if dct['emittance']['x'] != nemitt_x or dct['emittance']['y'] != nemitt_y:
250
+ raise ValueError("Emittance in CollimatorDatabase file different from "
251
+ + "'nemitt_x' and 'nemitt_y'!")
252
+
253
+ # Get family and collimator dicts
254
+ if 'families' in dct.keys():
255
+ if not 'collimators' in dct.keys():
256
+ raise ValueError("Could not find 'collimators' dict in CollimatorDatabase!")
257
+ fam = dct['families']
258
+ coll = dct['collimators']
259
+ elif 'collimators' in dct.keys():
260
+ coll = dct['collimators']
261
+ else:
262
+ coll = dct
263
+
264
+ return cls(collimator_dict=coll, family_dict=fam, nemitt_x=nemitt_x, nemitt_y=nemitt_y,
265
+ beam=beam, _yaml_merged=_yaml_merged, ignore_crystals=ignore_crystals)
266
+
267
+
268
+ @classmethod
269
+ def from_SixTrack(cls, file, ignore_crystals=True, **kwargs):
270
+ file = Path(file).resolve()
271
+ with file.open('r') as fp:
272
+ coll_data_string = ''
273
+ family_settings = {}
274
+ family_types = {}
275
+ side = {}
276
+ cry_fields = ['bending_radius', 'width', 'height', 'thick', 'tilt', 'miscut', 'crystal']
277
+ cry = {}
278
+
279
+ for line in fp:
280
+ if line.startswith('#'):
281
+ continue # Comment
282
+ sline = line.split()
283
+ if len(sline) > 0:
284
+ if sline[0].lower() == 'nsig_fam':
285
+ family_settings[sline[1]] = float(sline[2])
286
+ family_types[sline[1]] = sline[3]
287
+ elif sline[0].lower() == 'onesided':
288
+ side[sline[1]] = int(sline[2])
289
+ elif sline[0].lower() == "crystal":
290
+ cry[sline[1]] = {}
291
+ for i, key in enumerate(cry_fields):
292
+ idx = i+2
293
+ if i < 6:
294
+ cry[sline[1]][key] = float(sline[idx])
295
+ else:
296
+ cry[sline[1]][key] = int(sline[idx])
297
+ elif sline[0].lower() == 'settings':
298
+ pass # Acknowledge and ignore this line
299
+ elif len(sline) == 6:
300
+ # Standard collimator definition
301
+ coll_data_string += line
302
+ else:
303
+ print(f"Unknown setting {line}")
304
+
305
+ defaults = {}
306
+ _initialise_None(defaults)
307
+ defaults['thick'] = 0
308
+
309
+ famdct = {key: {'gap': None if family_settings[key] > 900 else family_settings[key],
310
+ 'stage': family_types[key]} for key in family_settings}
311
+ names = ['name', 'gap', 'material', 'length', 'angle', 'offset']
312
+
313
+ df = pd.read_csv(io.StringIO(coll_data_string), sep=r'\s+', index_col=False, names=names)
314
+ df['family'] = df['gap'].copy()
315
+ df['family'] = df['family'].apply(lambda s: None if re.match(r'^-?\d+(\.\d+)?$', str(s)) else s)
316
+ df.insert(5,'stage', df['gap'].apply(lambda s: None if s in family_types else 'UNKNOWN'))
317
+
318
+ df['gap'] = df['gap'].apply(lambda s: None if not isinstance(s, str) and s > 900 else s)
319
+ df['gap'] = df['gap'].apply(lambda s: None if isinstance(s, str) else s)
320
+
321
+ # TODO this breaks code if a key has upper case, e.g. gap_L
322
+ df['name'] = df['name'].str.lower() # Make the names lowercase for easy processing
323
+ df['parking'] = 0.025
324
+ if ignore_crystals:
325
+ df = df[~df.name.isin(list(cry.keys()))]
326
+ else:
327
+ for key in cry_fields:
328
+ df[key] = [cry[name][key] if name in cry else defaults[key]
329
+ for name in df['name']]
330
+ if not np.allclose(np.unique(df.thick.values), 0):
331
+ print("Warning: Keyword 'thick' is currently not supported in xcoll! Ignoring.")
332
+ df = df.drop('thick', axis=1)
333
+ df['crystal'] = ['strip' if s==1 else s for s in df['crystal']]
334
+ df['crystal'] = ['quasi-mosaic' if s==2 else s for s in df['crystal']]
335
+ df['side'] = [side[name] if name in side else defaults['side']
336
+ for name in df['name']]
337
+ df['side'] = ['both' if s==0 else s for s in df['side']]
338
+ df['side'] = ['left' if s==1 else s for s in df['side']]
339
+ df['side'] = ['right' if s==2 else s for s in df['side']]
340
+ if not np.allclose(np.unique(df.offset.values), 0):
341
+ print("Warning: Keyword 'offset' is currently not supported in xcoll! Ignoring.")
342
+ df = df.drop('offset', axis=1)
343
+ df = df.set_index('name')
344
+ df = df.replace(np.nan, None)
345
+
346
+ colldict = df.transpose().to_dict()
347
+ # Remove Nonetype families
348
+ colldict = {coll: {kk: vv for kk, vv in coll_settings.items()
349
+ if kk != 'family' or vv is not None}
350
+ for coll, coll_settings in colldict.items()}
351
+ # Remove None gaps and stages if the collimator is assigned a family (they will be set in _parse_dict)
352
+ colldict = {coll: {kk: vv for kk, vv in coll_settings.items()
353
+ if kk != 'gap' or vv is not None or 'family' not in coll_settings}
354
+ for coll, coll_settings in colldict.items()}
355
+ colldict = {coll: {kk: vv for kk, vv in coll_settings.items()
356
+ if kk != 'stage' or vv is not None or 'family' not in coll_settings}
357
+ for coll, coll_settings in colldict.items()}
358
+
359
+ return cls.from_dict({'collimators': colldict, 'families': famdct}, \
360
+ ignore_crystals=ignore_crystals, **kwargs)
361
+
362
+ def to_pandas(self):
363
+ return pd.DataFrame(self._collimator_dict).transpose()
364
+
365
+ def to_yaml(self, out, lhc_style=True):
366
+ """
367
+ Writes a colldb in memory to disk in the yaml format.
368
+
369
+ > colldb_object.write_to_yaml(<path+name>, lhc_style=Bool)
370
+
371
+ if lhc_style == True, it will add comments assuming that the collimators are named
372
+ as in the lhc.
373
+
374
+ The function can dump b1, b2 and a general bx, however multi-beam functionality is not yet
375
+ added to the collmanager. TODO
376
+
377
+ If any of the dumped keys contains capital letters (e.g. gap_L), it will not be possible
378
+ to load it back into xcoll, since all keys are set to lowercase when importing TODO
379
+ """
380
+ # Dumps collimator database to a YAML file with optional LHC style formatting
381
+ import re
382
+
383
+ # Local helper functions
384
+ def _format_dict_entry(key, value, spacing='', mapping=False, key_width=15):
385
+ # Formats a dictionary entry into a string for YAML output
386
+ formatted_values = ', '.join(f"{k}: {v}" for k, v in value.items())
387
+ formatted_values = re.sub(r'none', 'null', formatted_values, flags=re.IGNORECASE)
388
+ # Ensure key has a fixed width for alignment
389
+ if mapping:
390
+ formatted_key = f'{key}'.ljust(key_width)
391
+ else:
392
+ formatted_key = f'{key}:'.ljust(key_width)
393
+ #formatted_values = formatted_values.ljust(key_width)
394
+ return f"{spacing}{formatted_key} {{ {formatted_values} }}\n"
395
+
396
+ def _print_values(keys, dct, file, spacing='', mapping=False):
397
+ # Writes formatted dictionary entries to a file
398
+ for key in keys:
399
+ file.write(_format_dict_entry(key, dct[key], spacing=spacing, mapping=mapping))
400
+
401
+ def _print_colls(colls, dcts, beam, file):
402
+ # Filters and formats collimator data, then writes to a file
403
+ coll_items_to_print = ['<<','gap','angle','material','active','length','side']
404
+ file.write(f' {beam}:\n')
405
+ for coll in colls:
406
+ coll_dict = dcts.to_pandas().transpose().to_dict()[coll]
407
+ fam = coll_dict['family']
408
+ fam_keys = []
409
+ if fam is not None:
410
+ fam_keys = dcts._family_dict[fam].keys()
411
+ coll_dict = {**{'<<': '*'+fam}, **coll_dict}
412
+ temp_items_to_print = []
413
+ if coll_dict['crystal'] and str(coll_dict['crystal'])!='nan':
414
+ temp_items_to_print = ['bending_radius','width','height','miscut','crystal']
415
+ # if 'angle_L' in coll_dict and coll_dict['angle_L'] == coll_dict['angle_R']:
416
+ # coll_dict.update({'angle': coll_dict['angle_L']})
417
+ # else:
418
+ # temp_items_to_print = temp_items_to_print + ['angle_L','angle_R']
419
+ # if coll_dict['gap_L'] == coll_dict['gap_R']:
420
+ # coll_dict.update({'gap': coll_dict['gap_L']})
421
+ # elif coll_dict['gap_L'] is None and coll_dict['gap_R'] is not None:
422
+ # coll_dict.update({'gap': coll_dict['gap_R']})
423
+ # elif coll_dict['gap_L'] is not None and coll_dict['gap_R'] is None:
424
+ # coll_dict.update({'gap': coll_dict['gap_L']})
425
+ # else:
426
+ # temp_items_to_print = temp_items_to_print + ['gap_L','gap_R']
427
+ value = {}
428
+ overwritten_keys = coll_dict['overwritten_keys']
429
+ for key, val in coll_dict.items():
430
+ if key == 'active_length':
431
+ key = 'length'
432
+ if (key in coll_items_to_print+temp_items_to_print) and (key not in (set(fam_keys)-set(overwritten_keys))) and (val != 'both'):
433
+ value.update({key: val})
434
+ file.write(_format_dict_entry(coll, value, spacing=' '))
435
+ file.write('\n')
436
+
437
+ LHC_families = ['tcp3', 'tcsg3', 'tcsm3', 'tcla3', 'tcp7', 'tcsg7', 'tcsm7', 'tcla7', 'tcli', 'tdi', 'tcdq', 'tcstcdq', 'tcth1', 'tcth2', 'tcth5', 'tcth8', 'tctv1', 'tctv2', 'tctv5', 'tctv8', 'tclp', 'tcxrp', 'tcryo', 'tcl4', 'tcl5', 'tcl6', 'tct15', 'tct2', 'tct8', 'tcsp', 'tcld']
438
+ with open(f'{out}.yaml', 'w') as file:
439
+ if '_family_dict' in self.__dict__.keys():
440
+ file.write('families:\n')
441
+ if lhc_style:
442
+ printed_families = []
443
+ fams_in_dict = self._family_dict.keys()
444
+
445
+ # Momentum cleaning
446
+ file.write(' # Momentum cleaning\n')
447
+ sel_fam = [fam for fam in LHC_families if re.match('.*3', fam) and (fam in fams_in_dict)]
448
+ printed_families += sel_fam
449
+ _print_values(sel_fam, self._family_dict, file, spacing=' - &', mapping=True)
450
+
451
+ # Betatron cleaning
452
+ file.write(' # Betatron cleaning\n')
453
+ sel_fam = [fam for fam in LHC_families if re.match('.*7', fam) and (fam in fams_in_dict)]
454
+ printed_families += sel_fam
455
+ _print_values(sel_fam, self._family_dict, file, spacing=' - &', mapping=True)
456
+
457
+ # Injection protection
458
+ file.write(' # Injection protection\n')
459
+ sel_fam = [fam for fam in LHC_families if (fam in ['tcli', 'tdi']) and (fam in fams_in_dict)]
460
+ printed_families += sel_fam
461
+ _print_values(sel_fam, self._family_dict, file, spacing=' - &', mapping=True)
462
+
463
+ # Dump protection
464
+ file.write(' # Dump protection\n')
465
+ sel_fam = [fam for fam in LHC_families if (fam in ['tcdq', 'tcsp', 'tcstcdq']) and (fam in fams_in_dict)]
466
+ printed_families += sel_fam
467
+ _print_values(sel_fam, self._family_dict, file, spacing=' - &', mapping=True)
468
+
469
+ # Physics background / debris
470
+ file.write(' # Physics background / debris\n')
471
+ sel_fam = [fam for fam in LHC_families if ((re.match('tc[lt][0-9dp].*', fam)) or (fam in ['tcryo', 'tcxrp'])) and (fam in fams_in_dict)]
472
+ printed_families += sel_fam
473
+ _print_values(sel_fam, self._family_dict, file, spacing=' - &', mapping=True)
474
+
475
+ # Other families
476
+ if set(printed_families) != set(fams_in_dict):
477
+ file.write(' # Other families\n')
478
+ _print_values(set(fams_in_dict) - set(printed_families), self._family_dict, file, spacing=' - &', mapping=True)
479
+ else:
480
+ file.write(' # Families\n')
481
+ _print_values(self._family_dict.keys(), self._family_dict, file, spacing=' - &', mapping=True)
482
+
483
+ # Emittance section
484
+ ex = self.nemitt_x
485
+ ey = self.nemitt_y
486
+ file.write(f'\nemittance:\n x: {ex}\n y: {ey}\n')
487
+
488
+ # Collimators section
489
+ file.write('\ncollimators:\n')
490
+ b1_colls, b2_colls, bx_colls = [], [], []
491
+ for coll in self.to_pandas().index:
492
+ if coll == 'tclia.4r2' or coll == 'tclia.4l8': # TODO: hardcoded!!!
493
+ b1_colls.append(coll)
494
+ b2_colls.append(coll)
495
+ elif coll[-2:] == 'b1':
496
+ b1_colls.append(coll)
497
+ elif coll[-2:] == 'b2':
498
+ b2_colls.append(coll)
499
+ else:
500
+ bx_colls.append(coll)
501
+
502
+ # Handle special cases for collimators
503
+ if (('tclia.4r2' in b1_colls) or ('tclia.4l8' in b1_colls)) and (len(b1_colls) <= 2):
504
+ b1_colls = []
505
+ if (('tclia.4r2' in b2_colls) or ('tclia.4l8' in b2_colls)) and (len(b2_colls) <= 2):
506
+ b2_colls = []
507
+
508
+ # Print collimators for each beam
509
+ if len(b1_colls) > 0:
510
+ _print_colls(b1_colls, self, 'b1', file)
511
+ if len(b2_colls) > 0:
512
+ _print_colls(b2_colls, self, 'b2', file)
513
+ if len(bx_colls) > 0:
514
+ _print_colls(bx_colls, self, 'bx', file)
515
+ print('WARNING -- some collimators could not be assigned to b1 or b2. Tracking might not work with those collimators. Please manually change the output file if necessary.')
516
+
517
+
518
+ # ====================================
519
+ # ====== Installing collimators ======
520
+ # ====================================
521
+
522
+ def _get_names_from_line(self, line, names, families):
523
+ if names is None and families is None:
524
+ names = self.collimator_names
525
+ elif names is None:
526
+ names = self.get_collimators_from_family(families)
527
+ elif families is not None:
528
+ names.append(self.get_collimators_from_family(families))
529
+ return list(set(names)) # Remove duplicates
530
+
531
+ def _check_installed(self, line, name, collimator_class):
532
+ # Check that collimator is not installed as different type
533
+ # TODO: automatically replace collimator type and print warning
534
+ if isinstance(line[name], collimator_classes):
535
+ raise ValueError(f"Trying to install {name} as {collimator_class.__name__}, "
536
+ + f"but it is already installed as {line[name].__class__.__name__}!\n"
537
+ + f"Please reconstruct the line.")
538
+ # TODO: only allow Marker elements, no Drifts!!
539
+ # How to do this with importing a line for MAD-X or SixTrack...?
540
+ # Maybe we want a DriftCollimator type in Xtrack as a general placeholder
541
+ elif not isinstance(line[name], (xt.Marker, xt.Drift)):
542
+ raise ValueError(f"Trying to install {name} as {collimator_class.__name__}, "
543
+ + f"but the line element to replace is not an xtrack.Marker "
544
+ + f"(or xtrack.Drift)!\nPlease check the name, or correct the "
545
+ + f"element.")
546
+
547
+ def _create_collimator(self, line, collimator_class, name, **kwargs):
548
+ assert issubclass(collimator_class, BaseCollimator)
549
+ self._check_installed(line, name, collimator_class)
550
+ if kwargs.pop('verbose', False):
551
+ print(f"Installing {name:20} as {collimator_class.__name__}")
552
+ el = collimator_class(gap=self[name]['gap'], angle=self[name]['angle'],
553
+ length=self[name]['length'], side=self[name]['side'],
554
+ _tracking=False, **kwargs)
555
+ el.emittance = [self.nemitt_x, self.nemitt_y]
556
+ self._elements[name] = el
557
+
558
+ def _create_crystal(self, line, crystal_class, name, **kwargs):
559
+ assert issubclass(crystal_class, BaseCrystal)
560
+ self._check_installed(line, name, crystal_class)
561
+ if kwargs.pop('verbose', False):
562
+ print(f"Installing {name:20} as {crystal_class.__name__}")
563
+ el = crystal_class(gap=self[name]['gap'], angle=self[name]['angle'],
564
+ length=self[name]['length'], side=self[name]['side'],
565
+ bending_radius=self[name]['bending_radius'],
566
+ width=self[name]['width'], height=self[name]['height'],
567
+ _tracking=False, **kwargs)
568
+ el.emittance = [self.nemitt_x, self.nemitt_y]
569
+ self._elements[name] = el
570
+
571
+ def install_black_absorbers(self, line, *, names=None, families=None, verbose=False, need_apertures=True):
572
+ names = self._get_names_from_line(line, names, families)
573
+ for name in names:
574
+ if self[name]['bending_radius'] is None:
575
+ self._create_collimator(line, BlackAbsorber, name, verbose=verbose)
576
+ else:
577
+ self._create_crystal(line, BlackCrystal, name, verbose=verbose)
578
+ elements = [self._elements[name] for name in names]
579
+ line.collimators.install(names, elements, need_apertures=need_apertures)
580
+
581
+ def install_everest_collimators(self, line, *, names=None, families=None, verbose=False, need_apertures=True):
582
+ names = self._get_names_from_line(line, names, families)
583
+ for name in names:
584
+ mat = SixTrack_to_xcoll(self[name]['material'])
585
+ if self[name]['bending_radius'] is None:
586
+ self._create_collimator(line, EverestCollimator, name, material=mat[0],
587
+ verbose=verbose)
588
+ else:
589
+ self._create_crystal(line, EverestCrystal, name, material=mat[1],
590
+ lattice=self[name]['crystal'], verbose=verbose,
591
+ miscut=self[name]['miscut'])
592
+ elements = [self._elements[name] for name in names]
593
+ line.collimators.install(names, elements, need_apertures=need_apertures)
594
+
595
+ def install_fluka_collimators(self, line, *, names=None, families=None, verbose=False, need_apertures=True,
596
+ fluka_input_file=None, remove_missing=True):
597
+ # Check server
598
+ if FlukaEngine.is_running():
599
+ print("Warning: FLUKA server is already running. Stopping server to install collimators.")
600
+ FlukaEngine.stop_server(fluka_input_file)
601
+ names = self._get_names_from_line(line, names, families)
602
+ for name in names:
603
+ self._create_collimator(line, FlukaCollimator, name, verbose=verbose)
604
+ elements = [self._elements[name] for name in names]
605
+ line.collimators.install(names, elements, need_apertures=need_apertures)
606
+
607
+ # ==================================
608
+ # ====== Accessing attributes ======
609
+ # ==================================
610
+
611
+ @property
612
+ def collimator_names(self):
613
+ return list(self._collimator_dict.keys())
614
+
615
+ @property
616
+ def collimator_families(self):
617
+ families = {fam: [] for fam in self._family_dict.keys()}
618
+ families["no family"] = []
619
+ for name in self.collimator_names:
620
+ if 'family' not in self[name] or self[name]['family'].lower() == 'unknown':
621
+ families["no family"].append(name)
622
+ else:
623
+ families[self[name]['family']].append(name)
624
+ return families
625
+
626
+ def get_collimators_from_family(self, family):
627
+ if not hasattr(family, '__iter__') and not isinstance(family, str):
628
+ family = [family]
629
+ result = []
630
+ for fam in family:
631
+ if fam not in self.collimator_families:
632
+ raise ValueError(f"Family '{fam}' not found in CollimatorDatabase!")
633
+ result += self.collimator_families[fam]
634
+ return result
635
+
636
+ @property
637
+ def properties(self):
638
+ return {attr for d in self._collimator_dict.values() for attr in d.keys()}
639
+
640
+ def __getattr__(self, attr):
641
+ if attr in self.properties:
642
+ # TODO: include families
643
+ return {kk: vv.get(attr, None) for kk, vv in self._collimator_dict.items()}
644
+ else:
645
+ raise ValueError(f"Property `{attr}` not present in CollimatorDatabase!")
646
+
647
+ def __getitem__(self, name):
648
+ if name in self._family_dict:
649
+ return self._family_dict[name]
650
+ elif name in self._collimator_dict:
651
+ return self._collimator_dict[name]
652
+ else:
653
+ raise ValueError(f"Family nor collimator `{name}` found in CollimatorDatabase!")
654
+
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.5.7'
15
+ __version__ = '0.5.9'
16
16
  # ======================
@@ -0,0 +1,224 @@
1
+ # copyright ############################### #
2
+ # This file is part of the Xcoll package. #
3
+ # Copyright (c) CERN, 2024. #
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 _all_collimator_classes, EverestCrystal, FlukaCollimator
15
+ =======
16
+ from .beam_elements import collimator_classes, EverestCrystal
17
+ >>>>>>> release/v0.6.0
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, tw=None, **kwargs):
23
+ """
24
+ Generate a pencil beam on a collimator.
25
+ """
26
+
27
+ if not line._has_valid_tracker():
28
+ raise ValueError("Please build tracker before generating pencil distribution!")
29
+
30
+ coll = line[name]
31
+
32
+ if not isinstance(coll, tuple(collimator_classes)):
33
+ raise ValueError("Need to provide a valid collimator!")
34
+
35
+ if coll.optics is None:
36
+ raise ValueError("Need to assign optics to collimators before generating pencil distribution!")
37
+
38
+ num_particles = int(num_particles)
39
+ if len(line.get_elements_of_type(FlukaCollimator)[0]) > 0:
40
+ kwargs.setdefault('_capacity', 2*num_particles)
41
+
42
+ if coll.side == 'left':
43
+ side = '+'
44
+ if coll.side == 'right':
45
+ side = '-'
46
+
47
+ # Define the plane
48
+ angle = coll.angle
49
+ if abs(np.mod(angle-90,180)-90) < 1e-6:
50
+ plane = 'x'
51
+ transv_plane = 'y'
52
+ elif abs(np.mod(angle,180)-90) < 1e-6:
53
+ plane = 'y'
54
+ transv_plane = 'x'
55
+ else:
56
+ raise NotImplementedError("Pencil beam on a skew collimator not yet supported!")
57
+
58
+ if tw is not None:
59
+ warn("The argument tw is deprecated. Please use twiss instead.", FutureWarning)
60
+ if twiss is None:
61
+ twiss = tw
62
+
63
+ if twiss is None:
64
+ twiss = line.twiss()
65
+
66
+ # Is it converging or diverging? # TODO: This might change with a tilt!!!!!!
67
+ is_converging = twiss[f'alf{plane}', name] > 0
68
+ print(f"Collimator {name} is {'con' if is_converging else 'di'}verging.")
69
+
70
+ beam_sizes = twiss.get_beam_covariance(nemitt_x=coll.nemitt_x, nemitt_y=coll.nemitt_y)
71
+ if is_converging:
72
+ # pencil at front of jaw
73
+ sigma = beam_sizes.rows[name:f'{name}>>1'][f'sigma_{plane}'][0]
74
+ sigma_transv = beam_sizes.rows[name:f'{name}>>1'][f'sigma_{transv_plane}'][0]
75
+ tw_at_s = twiss.rows[name]
76
+ at_element = name
77
+ else:
78
+ # pencil at back of jaw
79
+ sigma = beam_sizes.rows[name:f'{name}>>1'][f'sigma_{plane}'][1]
80
+ sigma_transv = beam_sizes.rows[name:f'{name}>>1'][f'sigma_{transv_plane}'][1]
81
+ tw_at_s = twiss.rows[f'{name}>>1']
82
+ at_element = line.element_names[line.element_names.index(name)+1]
83
+
84
+ dr_sigmas = pencil_spread/sigma
85
+
86
+ # Generate 4D coordinates
87
+ # TODO: there is some looping in the calculation here and in xpart. Can it be improved?
88
+ if side == '+-':
89
+ num_plus = int(num_particles/2)
90
+ num_min = int(num_particles - num_plus)
91
+ coords_plus = _generate_4D_pencil_one_jaw(line, name, num_plus, plane, '+', impact_parameter, dr_sigmas, at_element, is_converging, tw_at_s)
92
+ coords_min = _generate_4D_pencil_one_jaw(line, name, num_min, plane, '-', impact_parameter, dr_sigmas, at_element, is_converging, tw_at_s)
93
+ coords = [ [*c_plus, *c_min] for c_plus, c_min in zip(coords_plus, coords_min)]
94
+ else:
95
+ coords = _generate_4D_pencil_one_jaw(line, name, num_particles, plane, side, impact_parameter, dr_sigmas, at_element, is_converging, tw_at_s)
96
+ pencil = coords[0]
97
+ p_pencil = coords[1]
98
+ transverse_norm = coords[2]
99
+ p_transverse_norm = coords[3]
100
+
101
+ # Longitudinal plane
102
+ # TODO: make this more general, make this better
103
+ if longitudinal is None:
104
+ delta = 0
105
+ zeta = 0
106
+ elif longitudinal == 'matched_dispersion':
107
+ raise NotImplementedError
108
+ # if longitudinal_betatron_cut is None:
109
+ # cut = 0
110
+ # else:
111
+ # cut = np.random.uniform(-longitudinal_betatron_cut, longitudinal_betatron_cut,
112
+ # num_particles)
113
+ # delta = generate_delta_from_dispersion(line, name, plane=plane, position_mm=pencil,
114
+ # nemitt_x=nemitt_x, nemitt_y=nemitt_y, twiss=tw,
115
+ # betatron_cut=cut, match_at_front=is_converging)
116
+ # zeta = 0
117
+ elif longitudinal == 'bucket':
118
+ zeta, delta = xp.generate_longitudinal_coordinates(
119
+ num_particles=num_particles, distribution='gaussian', sigma_z=sigma_z, line=line
120
+ )
121
+ elif not hasattr(longitudinal, '__iter__'):
122
+ raise ValueError
123
+ elif len(longitudinal) != 2:
124
+ raise ValueError
125
+ elif isinstance(longitudinal, str):
126
+ raise ValueError
127
+ elif isinstance(longitudinal, dict):
128
+ zeta = longitudinal['zeta']
129
+ delta = longitudinal['delta']
130
+ else:
131
+ zeta = longitudinal[0]
132
+ delta = longitudinal[1]
133
+
134
+ # Build the particles
135
+ if plane == 'x':
136
+ part = xp.build_particles(
137
+ x=pencil, px=p_pencil, y_norm=transverse_norm, py_norm=p_transverse_norm,
138
+ zeta=zeta, delta=delta, nemitt_x=coll.nemitt_x, nemitt_y=coll.nemitt_y,
139
+ line=line, at_element=at_element, _context=coll._buffer.context, **kwargs
140
+ )
141
+ else:
142
+ part = xp.build_particles(
143
+ x_norm=transverse_norm, px_norm=p_transverse_norm, y=pencil, py=p_pencil,
144
+ zeta=zeta, delta=delta, nemitt_x=coll.nemitt_x, nemitt_y=coll.nemitt_y,
145
+ line=line, at_element=at_element, _context=coll._buffer.context, **kwargs
146
+ )
147
+
148
+ part._init_random_number_generator()
149
+
150
+ if not is_converging:
151
+ dri = xt.Drift(length=-coll.length)
152
+ dri.track(part)
153
+ part.start_tracking_at_element -= 1
154
+ part.at_element -= 1
155
+
156
+ return part
157
+
158
+
159
+ def generate_delta_from_dispersion(line, at_element, *, plane, position_mm, nemitt_x, nemitt_y,
160
+ twiss=None, betatron_cut=0, match_at_front=True):
161
+ if line.tracker is None:
162
+ raise ValueError("Need to build tracker first!")
163
+ if not hasattr(betatron_cut, '__iter__'):
164
+ if hasattr(position_mm, '__iter__'):
165
+ betatron_cut = np.full_like(position_mm, betatron_cut)
166
+ elif not hasattr(position_mm, '__iter__'):
167
+ position_mm = np.full_like(betatron_cut, position_mm)
168
+ elif len(position_mm) != len(betatron_cut):
169
+ raise ValueError
170
+ if plane not in ['x', 'y']:
171
+ raise ValueError("The variable 'plane' needs to be either 'x' or 'y'!")
172
+
173
+ if twiss is None:
174
+ twiss = line.twiss()
175
+
176
+ beam_sizes = twiss.get_beam_covariance(nemitt_x=nemitt_x, nemitt_y=nemitt_y)
177
+ beam_sizes = beam_sizes.rows[at_element:f'{at_element}>>1'][f'sigma_{plane}']
178
+ sigma = beam_sizes[0] if match_at_front else beam_sizes[1]
179
+ delta = (position_mm - betatron_cut*sigma - twiss.rows[at_element][plane])
180
+ delta /= twiss.rows[at_element][f'd{plane}']
181
+
182
+ return delta
183
+
184
+
185
+ def _generate_4D_pencil_one_jaw(line, name, num_particles, plane, side, impact_parameter,
186
+ dr_sigmas, at_element, is_converging, tw_at_s=None):
187
+ coll = line[name]
188
+
189
+ if side == '+':
190
+ if is_converging:
191
+ if isinstance(coll, EverestCrystal):
192
+ pencil_pos = coll.jaw_U + impact_parameter
193
+ else:
194
+ pencil_pos = coll.jaw_LU + impact_parameter
195
+ else:
196
+ if isinstance(coll, EverestCrystal):
197
+ pencil_pos = coll.jaw_D - impact_parameter
198
+ else:
199
+ pencil_pos = coll.jaw_LD + impact_parameter
200
+ elif side == '-':
201
+ if is_converging:
202
+ if isinstance(coll, EverestCrystal):
203
+ pencil_pos = coll.jaw_U - impact_parameter
204
+ else:
205
+ pencil_pos = coll.jaw_RU - impact_parameter
206
+ else:
207
+ if isinstance(coll, EverestCrystal):
208
+ pencil_pos = coll.jaw_D + impact_parameter
209
+ else:
210
+ pencil_pos = coll.jaw_RD - impact_parameter
211
+
212
+ # Collimator plane: generate pencil distribution
213
+ pencil, p_pencil = xp.generate_2D_pencil_with_absolute_cut(
214
+ num_particles, plane=plane, absolute_cut=pencil_pos, line=line,
215
+ dr_sigmas=dr_sigmas, nemitt_x=coll.nemitt_x, nemitt_y=coll.nemitt_y,
216
+ at_element=at_element, side=side, twiss=tw_at_s
217
+ )
218
+
219
+ # Other plane: generate gaussian distribution in normalized coordinates
220
+ transverse_norm = np.random.normal(size=num_particles)
221
+ p_transverse_norm = np.random.normal(size=num_particles)
222
+
223
+ return [pencil, p_pencil, transverse_norm, p_transverse_norm]
224
+
@@ -238,14 +238,14 @@ class InteractionRecord(xt.BeamElement):
238
238
  'int': [shortcuts[inter] for inter in self._inter[mask]],
239
239
  'pid': self.id_before[mask]
240
240
  })
241
- return df.groupby('pid', sort=False)['int'].agg(list)
241
+ return df.groupby('pid', sort=False, group_keys=False)['int'].agg(list)
242
242
  else:
243
243
  df = pd.DataFrame({
244
244
  'int': [shortcuts[inter] for inter in self._inter[mask]],
245
245
  'turn': self.at_turn[mask],
246
246
  'pid': self.id_before[mask]
247
247
  })
248
- return df.groupby(['pid', 'turn'], sort=False)['int'].apply(list)
248
+ return df.groupby(['pid', 'turn'], sort=False, group_keys=False)['int'].apply(list)
249
249
 
250
250
  def first_touch_per_turn(self, frame=None):
251
251
  n_rows = self._index.num_recorded
@@ -253,7 +253,8 @@ class InteractionRecord(xt.BeamElement):
253
253
  'at_turn': self.at_turn[:n_rows],
254
254
  'at_element': self.at_element[:n_rows]})
255
255
  mask = np.char.startswith(self.interaction_type[:n_rows], 'Enter Jaw')
256
- idx_first = [group.at_element.idxmin() for _, group in df[mask].groupby(['at_turn', 'id_before'], sort=False)]
256
+ idx_first = [group.at_element.idxmin() for _, group in df[mask].groupby(
257
+ ['at_turn', 'id_before'], sort=False, group_keys=False)]
257
258
  df_first = self.to_pandas(frame=frame).loc[idx_first]
258
259
  df_first.insert(2, "jaw", df_first.interaction_type.astype(str).str[-1])
259
260
  to_drop = ['interaction_type',
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xcoll
3
- Version: 0.5.7
3
+ Version: 0.5.9
4
4
  Summary: Xsuite collimation package
5
5
  Home-page: https://github.com/xsuite/xcoll
6
6
  License: Apache 2.0
@@ -18,11 +18,10 @@ Provides-Extra: tests
18
18
  Requires-Dist: numpy (>=1.0)
19
19
  Requires-Dist: pandas (>=1.4)
20
20
  Requires-Dist: ruamel-yaml (>=0.17.31,<0.18.0) ; extra == "tests"
21
- Requires-Dist: xdeps (>=0.1.1)
22
- Requires-Dist: xfields (>=0.12.1)
23
- Requires-Dist: xobjects (>=0.2.6)
24
- Requires-Dist: xpart (>=0.15.0)
25
- Requires-Dist: xtrack (>=0.36.5)
21
+ Requires-Dist: xdeps (>=0.7.3)
22
+ Requires-Dist: xobjects (>=0.4.5)
23
+ Requires-Dist: xpart (>=0.19.1)
24
+ Requires-Dist: xtrack (>=0.69.7)
26
25
  Project-URL: Repository, https://github.com/xsuite/xcoll
27
26
  Description-Content-Type: text/markdown
28
27
 
@@ -3,7 +3,7 @@ NOTICE,sha256=6DO_E7WCdRKc42vUoVVBPGttvQi4mRt9fAcxj9u8zy8,74
3
3
  xcoll/__init__.py,sha256=b_61vh5irhf5fPmqTFJlyhNSt4rmftXg9uXPIEpgVB4,1612
4
4
  xcoll/_manager.py,sha256=9NQKaNxZR2I1ChMVBeKQc0A8h6W8gVgRRg72a5NgbXU,808
5
5
  xcoll/beam_elements/__init__.py,sha256=06bU8rzvlUPhcvwpaUippddm5IChpcCHBvpmvXJQU74,1122
6
- xcoll/beam_elements/__init__.py.orig,sha256=0R3TLw1J5WBsi5TdWOR4ERg4oD_WEzabJOF3lIsSkNc,1561
6
+ xcoll/beam_elements/__init__.py.orig,sha256=XZMbC-0IzLmKN4LXXT5zm2zOXzRWvkpuElCBGE3VWtw,1507
7
7
  xcoll/beam_elements/absorber.py,sha256=efK6gyUgD4x_FnBLpMR7-5_HCdp_753nkYikcdn6ulw,2502
8
8
  xcoll/beam_elements/base.py,sha256=6scwhofls5AHPJcUyEbTJOJ8U86EQU4S7BB7NGoE_j0,52728
9
9
  xcoll/beam_elements/blowup.py,sha256=gBXdlISvoDiMjXVpA77ls5QdAU3H9krwvFt2bSW_NII,8029
@@ -13,17 +13,19 @@ xcoll/beam_elements/elements_src/blowup.h,sha256=YlTt7YxswLM0ZjPuEjuE7xzjQ3hMt6F
13
13
  xcoll/beam_elements/elements_src/emittance_monitor.h,sha256=vlHzQFoUjKQHWBmzpaSzRbILtxSWqEasMtxHC-FFoAc,7078
14
14
  xcoll/beam_elements/elements_src/everest_block.h,sha256=iQ5_fyCil9Y4FJqccJdlqSVOHDtQNISQ_nTAJdGhqIs,6032
15
15
  xcoll/beam_elements/elements_src/everest_collimator.h,sha256=DlWkb5RORnp5VwI7E31Q7NLXRYDjXO1yPhTcSEMQgPg,9765
16
- xcoll/beam_elements/elements_src/everest_crystal.h,sha256=w1wHWhrvodvcJ2Atr8LSaVYHfCU3Y63KAjZZFFv87OI,12123
16
+ xcoll/beam_elements/elements_src/everest_crystal.h,sha256=WwwNF6it7TuOimhpSXJa7UXqp_i3wVZ_fXlTStn4db0,12193
17
17
  xcoll/beam_elements/everest.py,sha256=PA_VWpnPrIuO1xN__eKyT_ejbGZK7p93QHDVi3re7cM,8541
18
18
  xcoll/beam_elements/monitor.py,sha256=zzMdN3JMFSAs-30_ntRvd5qZGdsXfGtColhiFDuMcIk,16928
19
19
  xcoll/colldb.py,sha256=lEpkDRAT54szT9i7-jbTMRvkuW_0W2piZCdDaungcIs,30983
20
- xcoll/general.py,sha256=mUvu_vwD5Ds4anwH3YAZ1UgsV7O9qfGHpC0Gw-UW14k,534
20
+ xcoll/colldb.py.orig,sha256=v4AXbY44o_mlealtFXzMzDNLVt-Hkt_ZkjKs5QUJlec,31898
21
+ xcoll/general.py,sha256=-xLa-F2jd_1I3hIhlntMYsz_B-DZw_bj0qqh1SR1Cno,534
21
22
  xcoll/headers/checks.h,sha256=qdXsOTBOK1MwW6bdFF93j4yE648mcDtEv5rGN1w9sfk,1582
22
23
  xcoll/headers/particle_states.h,sha256=DZa_ZSaJrjnA8aHFriZKfRCkArQ8nK1t445MRwevDtA,840
23
24
  xcoll/initial_distribution.py,sha256=x5G4LTXn4boEg5jBFrQCk_l759h91XiAUhDTdcUvLkc,8779
25
+ xcoll/initial_distribution.py.orig,sha256=NOtDtAoNYx8p5l-hUO9ueafl3jtbIzGU0z8-xHtTX_E,9026
24
26
  xcoll/install.py,sha256=SxEFQnhWXlsXyPBIo847q6wPgId_f5ZtFRR1awGbkjc,2108
25
27
  xcoll/interaction_record/__init__.py,sha256=UFoLiKa-z2oX7YoszP-7Vgdt1nM6kT382v1CaIu8_u0,50
26
- xcoll/interaction_record/interaction_record.py,sha256=G2sFXgfmkgpDMaHWJaC80aAreHbY2rGhbkhaMhWKQBg,13192
28
+ xcoll/interaction_record/interaction_record.py,sha256=ixsQtVZn71vVEuTAA27a2NWcZZZ8iAcWFOa58bcWEQU,13271
27
29
  xcoll/interaction_record/interaction_record_src/interaction_record.h,sha256=0rNagnfSGc2i1jauOMIcDbj9QFic9dV_MOyqVx1kw5Q,6067
28
30
  xcoll/interaction_record/interaction_types.py,sha256=Vh6oFYKdRNOx9hc_E0iT8auNZVKC0qYVp_p7oyClZ8o,2894
29
31
  xcoll/line_tools.py,sha256=UtRVlwX1T-wzocFzgb3VoJuBavvggNnYONjvP2WigKM,14326
@@ -407,8 +409,8 @@ xcoll/scattering_routines/geometry/objects.h,sha256=A5ktGvVlSkC4hUsI_PQFsE80CuDw
407
409
  xcoll/scattering_routines/geometry/rotation.h,sha256=lO3RaQBys9r0ROMjR8T8Rr7UsIEm-H9_C_70Nwz4MXY,701
408
410
  xcoll/scattering_routines/geometry/segments.h,sha256=7nKnnin2ByxkKyaYwGvFaqgLQg5uBba4CdLHL7L3iQs,7667
409
411
  xcoll/scattering_routines/geometry/sort.h,sha256=b1MkFO2ddzv1fWGeQzsLuz46qo2pKyRSXHjoAEVU7Ts,5763
410
- xcoll-0.5.7.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
411
- xcoll-0.5.7.dist-info/METADATA,sha256=he1rkTbLF0vDWJhwNUkTY0VfScaFvpwucqKYVlKUwLs,2709
412
- xcoll-0.5.7.dist-info/NOTICE,sha256=6DO_E7WCdRKc42vUoVVBPGttvQi4mRt9fAcxj9u8zy8,74
413
- xcoll-0.5.7.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
414
- xcoll-0.5.7.dist-info/RECORD,,
412
+ xcoll-0.5.9.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
413
+ xcoll-0.5.9.dist-info/METADATA,sha256=ZBJuoHNhd-lFobMiSbj1SmSZ8yyie9OC_QTUo2Af4PI,2675
414
+ xcoll-0.5.9.dist-info/NOTICE,sha256=6DO_E7WCdRKc42vUoVVBPGttvQi4mRt9fAcxj9u8zy8,74
415
+ xcoll-0.5.9.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
416
+ xcoll-0.5.9.dist-info/RECORD,,
File without changes
File without changes
File without changes