xcoll 0.3.4__tar.gz → 0.3.5__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.

Potentially problematic release.


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

Files changed (110) hide show
  1. {xcoll-0.3.4 → xcoll-0.3.5}/PKG-INFO +1 -1
  2. {xcoll-0.3.4 → xcoll-0.3.5}/pyproject.toml +1 -1
  3. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/beam_elements/base.py +16 -0
  4. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/colldb.py +5 -6
  5. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/general.py +1 -1
  6. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/manager.py +5 -5
  7. xcoll-0.3.5/xcoll/rf_sweep.py +191 -0
  8. xcoll-0.3.4/xcoll/rf_sweep.py +0 -120
  9. {xcoll-0.3.4 → xcoll-0.3.5}/LICENSE +0 -0
  10. {xcoll-0.3.4 → xcoll-0.3.5}/NOTICE +0 -0
  11. {xcoll-0.3.4 → xcoll-0.3.5}/README.md +0 -0
  12. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/__init__.py +0 -0
  13. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/beam_elements/__init__.py +0 -0
  14. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/beam_elements/absorber.py +0 -0
  15. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/beam_elements/collimators_src/absorber.h +0 -0
  16. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/beam_elements/collimators_src/everest_block.h +0 -0
  17. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/beam_elements/collimators_src/everest_collimator.h +0 -0
  18. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/beam_elements/collimators_src/everest_crystal.h +0 -0
  19. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/beam_elements/everest.py +0 -0
  20. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/collimator_settings.py +0 -0
  21. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/headers/checks.h +0 -0
  22. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/headers/particle_states.h +0 -0
  23. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/impacts/__init__.py +0 -0
  24. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/impacts/impacts.py +0 -0
  25. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/impacts/impacts_src/impacts.h +0 -0
  26. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/impacts/interaction_types.py +0 -0
  27. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/everest/__init__.py +0 -0
  28. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/everest/constants.h +0 -0
  29. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/everest/crystal.h +0 -0
  30. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/everest/everest.h +0 -0
  31. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/everest/everest.py +0 -0
  32. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/everest/jaw.h +0 -0
  33. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/everest/materials.py +0 -0
  34. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/everest/multiple_coulomb_scattering.h +0 -0
  35. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/everest/properties.h +0 -0
  36. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/everest/scatter.h +0 -0
  37. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/everest/scatter_crystal.h +0 -0
  38. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/build_fluka_input.py +0 -0
  39. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/.git +0 -0
  40. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/.gitignore +0 -0
  41. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/CMakeLists.txt +0 -0
  42. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/ComponentMakefile +0 -0
  43. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/Makefile +0 -0
  44. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/README +0 -0
  45. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/doc/Doxyfile +0 -0
  46. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/doc/FlukaIO.asciidoc +0 -0
  47. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/doc/FlukaIO.epub +0 -0
  48. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/doc/FlukaIO.html +0 -0
  49. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/doc/FlukaIO.pdf +0 -0
  50. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/doc/FlukaIO__1.png +0 -0
  51. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/doc/FlukaIO__2.png +0 -0
  52. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/doc/FlukaIO__3.png +0 -0
  53. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/doc/FlukaIO__4.png +0 -0
  54. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/doc/FlukaIO__5.png +0 -0
  55. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/doc/FlukaIO__6.png +0 -0
  56. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/doc/FlukaIO__7.png +0 -0
  57. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/doc/Makefile +0 -0
  58. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/doc/docbook.xsl +0 -0
  59. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/include/Connection.h +0 -0
  60. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/include/FlukaIO.h +0 -0
  61. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/include/FlukaIOServer.h +0 -0
  62. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/include/FortranFlukaIO.h +0 -0
  63. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/include/Message.h +0 -0
  64. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/include/ParticleInfo.h +0 -0
  65. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/lib/libFlukaIO64.a +0 -0
  66. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/lib/libFlukaIO64.so +0 -0
  67. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/samples/ClientTest.c +0 -0
  68. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/samples/ServerTest.c +0 -0
  69. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/samples/fclient.f +0 -0
  70. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/samples/fserver.f +0 -0
  71. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/Connection.c +0 -0
  72. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/Connection.d +0 -0
  73. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/Connection.o +0 -0
  74. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/FlukaIO.c +0 -0
  75. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/FlukaIO.d +0 -0
  76. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/FlukaIO.o +0 -0
  77. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/FlukaIOHandshake.c +0 -0
  78. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/FlukaIOHandshake.d +0 -0
  79. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/FlukaIOHandshake.h +0 -0
  80. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/FlukaIOHandshake.o +0 -0
  81. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/FlukaIOServer.c +0 -0
  82. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/FlukaIOServer.d +0 -0
  83. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/FlukaIOServer.o +0 -0
  84. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/FlukaIOServer_private.h +0 -0
  85. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/FlukaIO_private.h +0 -0
  86. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/FortranFlukaIO.c +0 -0
  87. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/FortranFlukaIO.d +0 -0
  88. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/FortranFlukaIO.o +0 -0
  89. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/NetIO.c +0 -0
  90. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/NetIO.d +0 -0
  91. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/NetIO.h +0 -0
  92. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/NetIO.o +0 -0
  93. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/src/tags +0 -0
  94. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/tests/AllTests.cpp +0 -0
  95. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/tests/CommonTest.h +0 -0
  96. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/tests/ConnectionTest.cpp +0 -0
  97. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/tests/FlukaIOServerTest.cpp +0 -0
  98. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/tests/FlukaIOTest.cpp +0 -0
  99. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/tests/FortranFlukaIOTest.cpp +0 -0
  100. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/tests/fakes/FakeConnection.c +0 -0
  101. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/tests/fakes/FakeConnection.h +0 -0
  102. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/tests/fakes/FakeFlukaIO.c +0 -0
  103. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/tests/fakes/FakeFlukaIO.h +0 -0
  104. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/tests/fakes/FakeFlukaIOHandshake.c +0 -0
  105. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/tests/fakes/FakeFlukaIOHandshake.h +0 -0
  106. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/tests/fakes/FakeFlukaIOServer.c +0 -0
  107. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/tests/fakes/FakeFlukaIOServer.h +0 -0
  108. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/tests/fakes/FakeFortranFlukaIO.h +0 -0
  109. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/tests/fakes/FakeNetIO.c +0 -0
  110. {xcoll-0.3.4 → xcoll-0.3.5}/xcoll/scattering_routines/fluka/flukaio/tests/fakes/FakeNetIO.h +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: xcoll
3
- Version: 0.3.4
3
+ Version: 0.3.5
4
4
  Summary: Xsuite collimation package
5
5
  Home-page: https://github.com/xsuite/xcoll
6
6
  License: Apache 2.0
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "xcoll"
3
- version = "0.3.4"
3
+ version = "0.3.5"
4
4
  description = "Xsuite collimation package"
5
5
  homepage = "https://github.com/xsuite/xcoll"
6
6
  repository = "https://github.com/xsuite/xcoll"
@@ -60,6 +60,14 @@ class BaseBlock(xt.BeamElement):
60
60
  instance = super().__new__(cls)
61
61
  return instance
62
62
 
63
+ def enable_scattering(self):
64
+ if hasattr(self, '_tracking'):
65
+ self._tracking = True
66
+
67
+ def disable_scattering(self):
68
+ if hasattr(self, '_tracking'):
69
+ self._tracking = False
70
+
63
71
  def get_backtrack_element(self, _context=None, _buffer=None, _offset=None):
64
72
  return InvalidXcoll(length=-self.length,
65
73
  _context=_context, _buffer=_buffer, _offset=_offset)
@@ -196,6 +204,14 @@ class BaseCollimator(xt.BeamElement):
196
204
  super().__init__(**kwargs)
197
205
 
198
206
 
207
+ def enable_scattering(self):
208
+ if hasattr(self, '_tracking'):
209
+ self._tracking = True
210
+
211
+ def disable_scattering(self):
212
+ if hasattr(self, '_tracking'):
213
+ self._tracking = False
214
+
199
215
  @property
200
216
  def jaw(self):
201
217
  return _get_LR(self, 'jaw', neg=True)
@@ -214,9 +214,6 @@ class CollimatorDatabase:
214
214
  cry[sline[1]][key] = float(sline[idx])
215
215
  else:
216
216
  cry[sline[1]][key] = int(sline[idx])
217
- elif sline[0].lower() == "target":
218
- variables['xdim'][sline[1]] = float(sline[2])
219
- variables['ydim'][sline[1]] = float(sline[3])
220
217
  elif sline[0].lower() == 'settings':
221
218
  pass # Acknowledge and ignore this line
222
219
  elif len(sline) == 6:
@@ -231,7 +228,7 @@ class CollimatorDatabase:
231
228
  famdct = {key: {'gap': family_settings[key], 'stage': family_types[key]} for key in family_settings}
232
229
  names = ['name', 'gap', 'material', 'active_length', 'angle', 'offset']
233
230
 
234
- df = pd.read_csv(io.StringIO(coll_data_string), sep='\s+', index_col=False, names=names)
231
+ df = pd.read_csv(io.StringIO(coll_data_string), sep=r'\s+', index_col=False, names=names)
235
232
  df['family'] = df['gap'].copy()
236
233
  df['family'] = df['family'].apply(lambda s: None if re.match(r'^-?\d+(\.\d+)?$', str(s)) else s)
237
234
  df.insert(5,'stage', df['gap'].apply(lambda s: family_types.get(s, 'UNKNOWN')))
@@ -307,8 +304,8 @@ class CollimatorDatabase:
307
304
  fam_keys = dcts._family_dict[fam].keys()
308
305
  coll_dict = {**{'<<': '*'+fam}, **coll_dict}
309
306
  temp_items_to_print = []
310
- if coll_dict['crystal']:
311
- temp_items_to_print = ['bend','xdim','ydim','miscut','crystal']
307
+ if coll_dict['crystal'] and str(coll_dict['crystal'])!='nan':
308
+ temp_items_to_print = ['bending_radius','xdim','ydim','miscut','crystal', 'thick']
312
309
  if coll_dict['angle_L'] == coll_dict['angle_R']:
313
310
  coll_dict.update({'angle': coll_dict['angle_L']})
314
311
  else:
@@ -324,6 +321,8 @@ class CollimatorDatabase:
324
321
  value = {}
325
322
  overwritten_keys = coll_dict['overwritten_keys']
326
323
  for key, val in coll_dict.items():
324
+ if key == 'active_length':
325
+ key = 'length'
327
326
  if (key in coll_items_to_print+temp_items_to_print) and (key not in (set(fam_keys)-set(overwritten_keys))) and (val != 'both'):
328
327
  value.update({key: val})
329
328
  file.write(_format_dict_entry(coll, value, spacing=' '))
@@ -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.3.4'
15
+ __version__ = '0.3.5'
16
16
  # ===================
@@ -8,7 +8,7 @@ from pathlib import Path
8
8
  import numpy as np
9
9
  import pandas as pd
10
10
 
11
- from .beam_elements import BaseCollimator, BlackAbsorber, EverestCollimator, EverestCrystal, _all_collimator_types
11
+ from .beam_elements import BaseCollimator, BlackAbsorber, EverestCollimator, EverestCrystal, _all_collimator_types, element_classes
12
12
  from .colldb import CollimatorDatabase
13
13
  from .impacts import CollimatorImpacts
14
14
  from .scattering_routines.everest.materials import SixTrack_to_xcoll, CrystalMaterial
@@ -775,14 +775,14 @@ class CollimatorManager:
775
775
 
776
776
  def enable_scattering(self):
777
777
  # Prepare collimators for tracking
778
- for coll in self.collimator_names:
779
- self.line[coll]._tracking = True
778
+ for el in self.line.get_elements_of_type(element_classes)[0]:
779
+ el.enable_scattering()
780
780
  self._set_record_impacts()
781
781
 
782
782
  def disable_scattering(self):
783
783
  # Prepare collimators for tracking
784
- for coll in self.collimator_names:
785
- self.line[coll]._tracking = False
784
+ for el in self.line.get_elements_of_type(element_classes)[0]:
785
+ el.disable_scattering()
786
786
 
787
787
  @property
788
788
  def scattering_enabled(self):
@@ -0,0 +1,191 @@
1
+ # copyright ############################### #
2
+ # This file is part of the Xcoll Package. #
3
+ # Copyright (c) CERN, 2023. #
4
+ # ######################################### #
5
+
6
+ import numpy as np
7
+ import scipy.constants as sc
8
+ from time import perf_counter
9
+
10
+ import xtrack as xt
11
+ from xtrack.progress_indicator import progress
12
+
13
+ class RFSweep:
14
+
15
+ def __init__(self, line):
16
+ self.line = line
17
+ self._get_base_frequency()
18
+ self._install_zeta_shift()
19
+
20
+ def _get_base_frequency(self):
21
+ self.cavities = self.line.get_elements_of_type(xt.Cavity)[1]
22
+ freq = np.unique([round(self.line[cav].frequency, 9) for cav in self.cavities])
23
+ if len(freq) > 1:
24
+ raise NotImplementedError(f"Cannot sweep multiple cavities with different frequencies!")
25
+ elif abs(freq[0]) < 1e-9 :
26
+ raise ValueError(f"Cavity frequency not set!")
27
+ self.f_RF = freq[0]
28
+ phi = np.unique(np.array([self.line[cav].lag for cav in self.cavities])*np.pi/180.)
29
+ if len(phi) > 1:
30
+ raise NotImplementedError(f"Cannot sweep multiple cavities with different phases!")
31
+ self.phi = phi[0]
32
+ self.V = np.array([self.line[cav].voltage for cav in self.cavities]).sum()
33
+ self.L = self.line.get_length()
34
+
35
+ def _install_zeta_shift(self):
36
+ if 'rf_sweep' in self.line.element_names:
37
+ print(f"Found existing RF sweep in line.")
38
+ else:
39
+ s_cav = min([self.line.get_s_position(cav) for cav in self.cavities])
40
+ if self.line.tracker is not None:
41
+ self.line.unfreeze()
42
+ line_was_built = True
43
+ else:
44
+ line_was_built = False
45
+ self.line.insert_element(element=xt.ZetaShift(dzeta=0), name='rf_sweep', at_s=s_cav)
46
+ if line_was_built:
47
+ self.line.build_tracker()
48
+
49
+ @property
50
+ def current_sweep_value(self):
51
+ dzeta = self.line['rf_sweep'].dzeta
52
+ return round(self.f_RF * dzeta/(self.L-dzeta), 6)
53
+
54
+
55
+ def info(self, sweep=0, num_turns=0):
56
+ if abs(sweep) > 1e-9:
57
+ existing_sweep = self.current_sweep_value
58
+
59
+ beta0 = self.line.particle_ref.beta0[0]
60
+ E = self.line.particle_ref.energy0[0]
61
+ q = self.line.particle_ref.q0
62
+ h = self.f_RF * self.L / beta0 / sc.c
63
+ tw = self.line.twiss()
64
+ eta = tw.slip_factor
65
+
66
+ bucket_height = np.sqrt(abs(q*self.V*beta0**2 / (np.pi*h*eta*E) * (
67
+ 2*np.cos(self.phi) + (2*self.phi-np.pi)*np.sin(self.phi)
68
+ )))
69
+ delta_shift = -sweep / self.f_RF / eta
70
+ bucket_shift = delta_shift / bucket_height / 2
71
+ if num_turns > 0:
72
+ rf_shift_per_turn = sweep / num_turns
73
+ print(f"The current frequency is {self.f_RF + existing_sweep}Hz, adding {rf_shift_per_turn}Hz "
74
+ + f"per turn until {self.f_RF + existing_sweep + sweep} (for {num_turns} turns).")
75
+ print(f"This sweep will move the center of the bucket with \u0394\u03B4 = "
76
+ + f"{delta_shift} ({bucket_shift} buckets).")
77
+ if num_turns > 0 and num_turns < 3*bucket_shift/tw.qs:
78
+ print(f"Warning: This is a very fast sweep, moving ~{round(bucket_shift, 2)} buckets in "
79
+ + f"~{round(num_turns*tw.qs, 2)} synchrotron oscillations (on average). If the "
80
+ + f"bucket moves faster than a particle can follow, that particle will move out of "
81
+ + f"the bucket and remain uncaptured.")
82
+
83
+
84
+ def track(self, sweep=0, particles=None, num_turns=0, verbose=True, *args, **kwargs):
85
+
86
+ # Was there a previous sweep?
87
+ # If yes, we do not overwrite it but continue from there
88
+ existing_sweep = self.current_sweep_value
89
+
90
+ # Just set the new RF frequency, no tracking
91
+ if num_turns == 0:
92
+ sweep += existing_sweep
93
+ if verbose:
94
+ print(f"The current frequency is {self.f_RF + existing_sweep}Hz, moving to {self.f_RF + sweep}Hz."
95
+ + "No tracking performed.")
96
+ self.line['rf_sweep'].dzeta = self.L * sweep / (self.f_RF + sweep)
97
+
98
+ # Sweep and track
99
+ else:
100
+ if self.line.tracker is None:
101
+ raise ValueError("Need to build tracker first!")
102
+ if particles is None:
103
+ raise ValueError("Need particles to track!")
104
+ time = kwargs.pop('time', False)
105
+ with_progress = kwargs.pop('with_progress', False)
106
+ rf_shift_per_turn = sweep / num_turns
107
+
108
+ # This is taken from xtrack.tracker.Tracker._track
109
+ if time:
110
+ t0 = perf_counter()
111
+ if with_progress:
112
+ if self.line.tracker.enable_pipeline_hold:
113
+ raise ValueError("Progress indicator is not supported with pipeline hold")
114
+ if num_turns < 2:
115
+ raise ValueError('Tracking with progress indicator is only '
116
+ 'possible over more than one turn.')
117
+ if with_progress is True:
118
+ batch_size = scaling = 100
119
+ else:
120
+ batch_size = int(with_progress)
121
+ scaling = with_progress if batch_size > 1 else None
122
+ if kwargs.get('turn_by_turn_monitor') is True:
123
+ ele_start = kwargs.get('ele_start') or 0
124
+ ele_stop = kwargs.get('ele_stop')
125
+ if ele_stop is None:
126
+ ele_stop = len(self.line)
127
+ if ele_start >= ele_stop:
128
+ # we need an additional turn and space in the monitor for
129
+ # the incomplete turn
130
+ num_turns += 1
131
+ _, monitor, _, _ = self.line.tracker._get_monitor(particles, True, num_turns)
132
+ kwargs['turn_by_turn_monitor'] = monitor
133
+
134
+ for ii in progress(
135
+ range(0, num_turns, batch_size),
136
+ desc='Tracking',
137
+ unit_scale=scaling,
138
+ ):
139
+ one_turn_kwargs = kwargs.copy()
140
+ is_first_batch = ii == 0
141
+ is_last_batch = ii + batch_size >= num_turns
142
+
143
+ if is_first_batch and is_last_batch:
144
+ # This is the only batch, we track as normal
145
+ pass
146
+ elif is_first_batch:
147
+ # Not the last batch, so track until the last element
148
+ one_turn_kwargs['ele_stop'] = None
149
+ one_turn_kwargs['num_turns'] = batch_size
150
+ elif is_last_batch:
151
+ # Not the first batch, so track from the first element
152
+ one_turn_kwargs['ele_start'] = None
153
+ remaining_turns = num_turns % batch_size
154
+ if remaining_turns == 0:
155
+ remaining_turns = batch_size
156
+ one_turn_kwargs['num_turns'] = remaining_turns
157
+ one_turn_kwargs['_reset_log'] = False
158
+ elif not is_first_batch and not is_last_batch:
159
+ # A 'middle batch', track from first to last element
160
+ one_turn_kwargs['num_turns'] = batch_size
161
+ one_turn_kwargs['ele_start'] = None
162
+ one_turn_kwargs['ele_stop'] = None
163
+ one_turn_kwargs['_reset_log'] = False
164
+ self._tracking_func(particles, rf_shift_per_turn, **one_turn_kwargs)
165
+ if not np.any(particles.state == 1):
166
+ break
167
+
168
+ else:
169
+ self._tracking_func(particles, rf_shift_per_turn, num_turns=num_turns, *args, **kwargs)
170
+
171
+ if not np.any(particles.state == 1):
172
+ print(f"All particles lost at turn {particles.at_turn.max()}, stopped sweep at "
173
+ + f"{self.current_sweep_value}Hz.")
174
+
175
+ if time:
176
+ t1 = perf_counter()
177
+ self.line.tracker._context.synchronize()
178
+ self.line.tracker.time_last_track = t1 - t0
179
+ else:
180
+ self.line.tracker.time_last_track = None
181
+
182
+ def _tracking_func(self, particles, rf_shift_per_turn, num_turns=1, *args, **kwargs):
183
+ existing_sweep = self.current_sweep_value
184
+ for i in range(num_turns):
185
+ sweep = existing_sweep + i*rf_shift_per_turn
186
+ self.line['rf_sweep'].dzeta = self.L * sweep / (self.f_RF + sweep)
187
+ # for cav in cavities:
188
+ # self.line[cav].frequency = freq + sweep
189
+ self.line.track(particles, num_turns=1, *args, **kwargs)
190
+ if not np.any(particles.state == 1):
191
+ break
@@ -1,120 +0,0 @@
1
- # copyright ############################### #
2
- # This file is part of the Xcoll Package. #
3
- # Copyright (c) CERN, 2023. #
4
- # ######################################### #
5
-
6
- import numpy as np
7
- import pandas as pd
8
- import scipy.constants as sc
9
-
10
- import xtrack as xt
11
-
12
-
13
- class RFSweep:
14
-
15
- def __init__(self, line):
16
- self.line = line
17
- self._get_base_frequency()
18
- self._install_zeta_shift()
19
-
20
- def _get_base_frequency(self):
21
- self.cavities = self.line.get_elements_of_type(xt.Cavity)[1]
22
- freq = np.unique([round(self.line[cav].frequency, 9) for cav in self.cavities])
23
- if len(freq) > 1:
24
- raise NotImplementedError(f"Cannot sweep multiple cavities with different frequencies!")
25
- elif abs(freq[0]) < 1e-9 :
26
- raise ValueError(f"Cavity frequency not set!")
27
- self.f_RF = freq[0]
28
- phi = np.unique(np.array([self.line[cav].lag for cav in self.cavities])*np.pi/180.)
29
- if len(phi) > 1:
30
- raise NotImplementedError(f"Cannot sweep multiple cavities with different phases!")
31
- self.phi = phi[0]
32
- self.V = np.array([self.line[cav].voltage for cav in self.cavities]).sum()
33
- self.L = self.line.get_length()
34
-
35
- def _install_zeta_shift(self):
36
- if 'rf_sweep' in self.line.element_names:
37
- print(f"Found existing RF sweep in line.")
38
- else:
39
- s_cav = min([self.line.get_s_position(cav) for cav in self.cavities])
40
- if self.line.tracker is not None:
41
- self.line.unfreeze()
42
- line_was_built = True
43
- else:
44
- line_was_built = False
45
- self.line.insert_element(element=xt.ZetaShift(dzeta=0), name='rf_sweep', at_s=s_cav)
46
- if line_was_built:
47
- self.line.build_tracker()
48
-
49
- @property
50
- def current_sweep_value(self):
51
- dzeta = self.line['rf_sweep'].dzeta
52
- return round(self.f_RF * dzeta/(self.L-dzeta), 6)
53
-
54
-
55
- def info(self, sweep=0, num_turns=0):
56
- if abs(sweep) > 1e-9:
57
- existing_sweep = self.current_sweep_value
58
-
59
- beta0 = self.line.particle_ref.beta0[0]
60
- E = self.line.particle_ref.energy0[0]
61
- q = self.line.particle_ref.q0
62
- h = self.f_RF * self.L / beta0 / sc.c
63
- tw = self.line.twiss()
64
- eta = tw.slip_factor
65
-
66
- bucket_height = np.sqrt(abs(q*self.V*beta0**2 / (np.pi*h*eta*E) * (
67
- 2*np.cos(self.phi) + (2*self.phi-np.pi)*np.sin(self.phi)
68
- )))
69
- delta_shift = -sweep / self.f_RF / eta
70
- bucket_shift = delta_shift / bucket_height / 2
71
- if num_turns > 0:
72
- rf_shift_per_turn = sweep / num_turns
73
- print(f"The current frequency is {self.f_RF + existing_sweep}Hz, adding {rf_shift_per_turn}Hz "
74
- + f"per turn until {self.f_RF + existing_sweep + sweep} (for {num_turns} turns).")
75
- print(f"This sweep will move the center of the bucket with \u0394\u03B4 = "
76
- + f"{delta_shift} ({bucket_shift} buckets).")
77
- if num_turns > 0 and num_turns < 3*bucket_shift/tw.qs:
78
- print(f"Warning: This is a very fast sweep, moving ~{round(bucket_shift, 2)} buckets in "
79
- + f"~{round(num_turns*tw.qs, 2)} synchrotron oscillations (on average). If the "
80
- + f"bucket moves faster than a particle can follow, that particle will move out of "
81
- + f"the bucket and remain uncaptured.")
82
-
83
-
84
- def track(self, sweep=0, num_turns=0, particles=None, verbose=True, *args, **kwargs):
85
-
86
- # Was there a previous sweep?
87
- # If yes, we do not overwrite it but continue from there
88
- existing_sweep = self.current_sweep_value
89
-
90
- # Just set the new RF frequency, no tracking
91
- if num_turns == 0:
92
- sweep += existing_sweep
93
- if verbose:
94
- print(f"The current frequency is {self.f_RF + existing_sweep}Hz, moving to {self.f_RF + sweep}Hz."
95
- + "No tracking performed.")
96
- self.line['rf_sweep'].dzeta = self.L * sweep / (self.f_RF + sweep)
97
-
98
- # Sweep and track
99
- else:
100
- if self.line.tracker is None:
101
- raise ValueError("Need to build tracker first!")
102
- if particles is None:
103
- raise ValueError("Need particles to track!")
104
- rf_shift_per_turn = sweep / num_turns
105
- if 'time' in kwargs and kwargs['time']:
106
- self.line.tracker.time_last_track = 0
107
- for i in range(num_turns):
108
- sweep = existing_sweep + i*rf_shift_per_turn
109
- self.line['rf_sweep'].dzeta = self.L * sweep / (self.f_RF + sweep)
110
- # for cav in cavities:
111
- # self.line[cav].frequency = freq + sweep
112
- if 'time' in kwargs and kwargs['time']:
113
- prev_time = self.line.time_last_track
114
- self.line.track(particles, num_turns=1, *args, **kwargs)
115
- if 'time' in kwargs and kwargs['time']:
116
- self.line.tracker.time_last_track += prev_time
117
- if not np.any(particles.state == 1):
118
- print(f"All particles lost at turn {i}, stopped sweep at "
119
- + f"{existing_sweep + i*rf_shift_per_turn}Hz.")
120
- break
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes