xtrack 0.41.2__tar.gz → 0.42.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {xtrack-0.41.2/xtrack.egg-info → xtrack-0.42.0}/PKG-INFO +1 -1
- xtrack-0.42.0/xtrack/_version.py +1 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements.py +108 -3
- xtrack-0.42.0/xtrack/beam_elements/elements_src/solenoid.h +151 -0
- xtrack-0.42.0/xtrack/footprint.py +382 -0
- xtrack-0.42.0/xtrack/headers/atomicadd.h +41 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/line.py +32 -12
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/mad_loader.py +15 -1
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/match.py +2 -2
- xtrack-0.42.0/xtrack/monitors/__init__.py +6 -0
- xtrack-0.42.0/xtrack/monitors/beam_position_monitor.h +67 -0
- xtrack-0.42.0/xtrack/monitors/beam_position_monitor.py +138 -0
- xtrack-0.42.0/xtrack/monitors/beam_profile_monitor.h +88 -0
- xtrack-0.42.0/xtrack/monitors/beam_profile_monitor.py +209 -0
- xtrack-0.42.0/xtrack/monitors/beam_size_monitor.h +69 -0
- xtrack-0.42.0/xtrack/monitors/beam_size_monitor.py +151 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/slicing.py +33 -12
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/survey.py +5 -5
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/tracker.py +17 -11
- {xtrack-0.41.2 → xtrack-0.42.0/xtrack.egg-info}/PKG-INFO +1 -1
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack.egg-info/SOURCES.txt +8 -0
- xtrack-0.41.2/xtrack/_version.py +0 -1
- xtrack-0.41.2/xtrack/footprint.py +0 -197
- xtrack-0.41.2/xtrack/monitors/__init__.py +0 -3
- {xtrack-0.41.2 → xtrack-0.42.0}/LICENSE +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/MANIFEST.in +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/README.md +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/ducktrack/__init__.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/ducktrack/base_classes.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/ducktrack/be_beamfields/BB6D.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/ducktrack/be_beamfields/BB6Ddata.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/ducktrack/be_beamfields/__init__.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/ducktrack/be_beamfields/beambeam.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/ducktrack/be_beamfields/boost.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/ducktrack/be_beamfields/gaussian_fields.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/ducktrack/be_beamfields/propagate_sigma_matrix.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/ducktrack/be_beamfields/qgauss.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/ducktrack/be_beamfields/slicing.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/ducktrack/be_beamfields/spacecharge.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/ducktrack/elements.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/ducktrack/line.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/ducktrack/mathlibs.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/ducktrack/particles.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/ducktrack/temp_pyparticles.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/pyproject.toml +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/setup.cfg +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/setup.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/__init__.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/_temp/__init__.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/_temp/lhc_match/__init__.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/_temp/lhc_match/gen_madx_optics_file.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/_temp/lhc_match/lhc_match.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/_temp/lhc_match/var_limits.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/base_element.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/__init__.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/apertures.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/apertures_src/limitellipse.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/apertures_src/limitpolygon.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/apertures_src/limitracetrack.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/apertures_src/limitrect.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/apertures_src/limitrectellipse.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/apertures_src/longitudinallimitrect.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/beam_interaction.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/bend.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/cavity.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/combinedfunctionmagnet.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/dipoleedge.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/drift.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/drift_elem.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/elens.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/exciter.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/firstordertaylormap.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/fringe.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/fringe_track.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/lineartransfermatrix.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/linesegmentmap.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/multipolar_kick.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/multipole.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/nonlinearlens.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/quadrupole.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/referenceenergyincrease.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/rfmultipole.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/sextupole.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/simplethinbend.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/simplethinquadrupole.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/srotation.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/track_thick_bend.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/track_thick_cfd.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/track_yrotation.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/wedge.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/wedge_track.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/wire.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/xrotation.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/xyshift.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/yrotation.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/elements_src/zetashift.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/beam_elements/exciter.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/compounds.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/general.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/headers/checks.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/headers/constants.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/headers/particle_states.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/headers/synrad_spectrum.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/internal_record.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/linear_normal_form.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/loss_location_refinement/__init__.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/loss_location_refinement/loss_location_refinement.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/lumi.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/monitors/last_turns_monitor.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/monitors/last_turns_monitor.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/monitors/particles_monitor.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/monitors/particles_monitor.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/multiline/__init__.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/multiline/multiline.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/multiline/shared_knobs.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/multisetter/__init__.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/multisetter/multisetter.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/pipeline/__init__.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/pipeline/core.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/pipeline/manager.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/pipeline/multitracker.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/prebuild_kernels.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/prebuilt_kernels/__init__.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/prebuilt_kernels/kernel_definitions.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/random/__init__.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/random/random_generators.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/random/random_src/exponential.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/random/random_src/exponential_integral_Ei.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/random/random_src/normal.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/random/random_src/rutherford.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/random/random_src/uniform.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/tapering.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/targets.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/tracker_data.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/tracker_src/tracker.h +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack/twiss.py +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack.egg-info/dependency_links.txt +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack.egg-info/requires.txt +0 -0
- {xtrack-0.41.2 → xtrack-0.42.0}/xtrack.egg-info/top_level.txt +0 -0
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = '0.42.0'
|
@@ -78,9 +78,6 @@ class Drift(BeamElement):
|
|
78
78
|
_pkg_root.joinpath('beam_elements/elements_src/drift_elem.h'),
|
79
79
|
]
|
80
80
|
|
81
|
-
def make_slice(self, weight):
|
82
|
-
return Drift(length=self.length * weight)
|
83
|
-
|
84
81
|
@staticmethod
|
85
82
|
def add_slice(weight, container, thick_name, slice_name, _buffer=None):
|
86
83
|
container[slice_name] = Drift(_buffer=_buffer)
|
@@ -873,6 +870,27 @@ class CombinedFunctionMagnet(BeamElement):
|
|
873
870
|
ref.length = _get_expr(self_or_ref.length) * weight
|
874
871
|
ref.order = order
|
875
872
|
|
873
|
+
@classmethod
|
874
|
+
def add_thick_slice(cls, weight, container, name, slice_name, _buffer=None):
|
875
|
+
self_or_ref = container[name]
|
876
|
+
container[slice_name] = cls(
|
877
|
+
length=self_or_ref.length * weight,
|
878
|
+
num_multipole_kicks=self_or_ref.num_multipole_kicks,
|
879
|
+
order=self_or_ref.order,
|
880
|
+
_buffer=_buffer,
|
881
|
+
)
|
882
|
+
ref = container[slice_name]
|
883
|
+
|
884
|
+
ref.k0 = _get_expr(self_or_ref.k0)
|
885
|
+
ref.k1 = _get_expr(self_or_ref.k1)
|
886
|
+
ref.h = _get_expr(self_or_ref.h)
|
887
|
+
|
888
|
+
for ii in range(len(self_or_ref.knl)):
|
889
|
+
ref.knl[ii] = _get_expr(self_or_ref.knl[ii]) * weight
|
890
|
+
|
891
|
+
for ii in range(len(self_or_ref.ksl)):
|
892
|
+
ref.ksl[ii] = _get_expr(self_or_ref.ksl[ii]) * weight
|
893
|
+
|
876
894
|
@staticmethod
|
877
895
|
def delete_element_ref(ref):
|
878
896
|
# Remove the array fields
|
@@ -1048,6 +1066,25 @@ class Quadrupole(BeamElement):
|
|
1048
1066
|
ref.length = _get_expr(self_or_ref.length) * weight
|
1049
1067
|
ref.order = order
|
1050
1068
|
|
1069
|
+
@classmethod
|
1070
|
+
def add_thick_slice(cls, weight, container, name, slice_name, _buffer=None):
|
1071
|
+
self_or_ref = container[name]
|
1072
|
+
container[slice_name] = cls(
|
1073
|
+
length=self_or_ref.length * weight,
|
1074
|
+
num_multipole_kicks=self_or_ref.num_multipole_kicks,
|
1075
|
+
order=self_or_ref.order,
|
1076
|
+
_buffer=_buffer,
|
1077
|
+
)
|
1078
|
+
ref = container[slice_name]
|
1079
|
+
|
1080
|
+
ref.k1 = _get_expr(self_or_ref.k1)
|
1081
|
+
|
1082
|
+
for ii in range(len(self_or_ref.knl)):
|
1083
|
+
ref.knl[ii] = _get_expr(self_or_ref.knl[ii]) * weight
|
1084
|
+
|
1085
|
+
for ii in range(len(self_or_ref.ksl)):
|
1086
|
+
ref.ksl[ii] = _get_expr(self_or_ref.ksl[ii]) * weight
|
1087
|
+
|
1051
1088
|
@staticmethod
|
1052
1089
|
def delete_element_ref(ref):
|
1053
1090
|
# Remove the array fields
|
@@ -1065,6 +1102,53 @@ class Quadrupole(BeamElement):
|
|
1065
1102
|
_unregister_if_preset(ref)
|
1066
1103
|
|
1067
1104
|
|
1105
|
+
class Solenoid(BeamElement):
|
1106
|
+
isthick = True
|
1107
|
+
|
1108
|
+
_xofields = {
|
1109
|
+
'length': xo.Float64,
|
1110
|
+
'ks': xo.Float64,
|
1111
|
+
'ksi': xo.Float64,
|
1112
|
+
}
|
1113
|
+
|
1114
|
+
_extra_c_sources = [
|
1115
|
+
_pkg_root.joinpath('beam_elements/elements_src/drift.h'),
|
1116
|
+
_pkg_root.joinpath('beam_elements/elements_src/solenoid.h'),
|
1117
|
+
]
|
1118
|
+
|
1119
|
+
def __init__(self, length=0, ks=0, ksi=0, **kwargs):
|
1120
|
+
"""
|
1121
|
+
Solenoid element.
|
1122
|
+
|
1123
|
+
Parameters
|
1124
|
+
----------
|
1125
|
+
length : float
|
1126
|
+
Length of the element in meters.
|
1127
|
+
ks : float
|
1128
|
+
Strength of the solenoid component in rad / m. Only to be specified
|
1129
|
+
when the element is thin, i.e. when `length` == 0.
|
1130
|
+
ksi : float
|
1131
|
+
Integrated strength of the solenoid component in rad.
|
1132
|
+
"""
|
1133
|
+
|
1134
|
+
if '_xobject' in kwargs.keys() and kwargs['_xobject'] is not None:
|
1135
|
+
self.xoinitialize(**kwargs)
|
1136
|
+
return
|
1137
|
+
|
1138
|
+
if length == 0:
|
1139
|
+
# Fail when trying to create a thin solenoid, as these are not
|
1140
|
+
# tested yet
|
1141
|
+
raise NotImplementedError('Thin solenoids are not implemented yet.')
|
1142
|
+
# self.isthick = False
|
1143
|
+
|
1144
|
+
if ksi and length:
|
1145
|
+
raise ValueError(
|
1146
|
+
"The parameter `ksi` can only be specified when `length` == 0."
|
1147
|
+
)
|
1148
|
+
|
1149
|
+
self.xoinitialize(length=length, ks=ks, ksi=ksi, **kwargs)
|
1150
|
+
|
1151
|
+
|
1068
1152
|
class Bend(BeamElement):
|
1069
1153
|
isthick = True
|
1070
1154
|
has_backtrack = True
|
@@ -1204,6 +1288,27 @@ class Bend(BeamElement):
|
|
1204
1288
|
ref.length = _get_expr(self_or_ref.length) * weight
|
1205
1289
|
ref.order = order
|
1206
1290
|
|
1291
|
+
@classmethod
|
1292
|
+
def add_thick_slice(cls, weight, container, name, slice_name, _buffer=None):
|
1293
|
+
self_or_ref = container[name]
|
1294
|
+
container[slice_name] = cls(
|
1295
|
+
length=self_or_ref.length * weight,
|
1296
|
+
num_multipole_kicks=self_or_ref.num_multipole_kicks,
|
1297
|
+
order=self_or_ref.order,
|
1298
|
+
_buffer=_buffer,
|
1299
|
+
)
|
1300
|
+
ref = container[slice_name]
|
1301
|
+
|
1302
|
+
ref.k0 = _get_expr(self_or_ref.k0)
|
1303
|
+
ref.h = _get_expr(self_or_ref.h)
|
1304
|
+
ref.length = _get_expr(self_or_ref.length) * weight
|
1305
|
+
|
1306
|
+
for ii in range(len(self_or_ref.knl)):
|
1307
|
+
ref.knl[ii] = _get_expr(self_or_ref.knl[ii]) * weight
|
1308
|
+
|
1309
|
+
for ii in range(len(self_or_ref.ksl)):
|
1310
|
+
ref.ksl[ii] = _get_expr(self_or_ref.ksl[ii]) * weight
|
1311
|
+
|
1207
1312
|
@staticmethod
|
1208
1313
|
def delete_element_ref(ref):
|
1209
1314
|
# Remove the array fields
|
@@ -0,0 +1,151 @@
|
|
1
|
+
// copyright ############################### //
|
2
|
+
// This file is part of the Xtrack Package. //
|
3
|
+
// Copyright (c) CERN, 2023. //
|
4
|
+
// ######################################### //
|
5
|
+
|
6
|
+
#ifndef XTRACK_SOLENOID_H
|
7
|
+
#define XTRACK_SOLENOID_H
|
8
|
+
|
9
|
+
#define IS_ZERO(X) (fabs(X) < 1e-9)
|
10
|
+
|
11
|
+
/*gpufun*/
|
12
|
+
void Solenoid_thin_track_single_particle(LocalParticle*, double, double, double);
|
13
|
+
|
14
|
+
/*gpufun*/
|
15
|
+
void Solenoid_thick_track_single_particle(LocalParticle*, double, double);
|
16
|
+
|
17
|
+
|
18
|
+
/*gpufun*/
|
19
|
+
void Solenoid_track_local_particle(SolenoidData el, LocalParticle* part0) {
|
20
|
+
// Parameters
|
21
|
+
const double length = SolenoidData_get_length(el);
|
22
|
+
const double ks = SolenoidData_get_ks(el);
|
23
|
+
const double ksi = SolenoidData_get_ksi(el);
|
24
|
+
|
25
|
+
if (IS_ZERO(length)) {
|
26
|
+
//start_per_particle_block (part0->part)
|
27
|
+
Solenoid_thin_track_single_particle(part, length, ks, ksi);
|
28
|
+
//end_per_particle_block
|
29
|
+
}
|
30
|
+
else {
|
31
|
+
//start_per_particle_block (part0->part)
|
32
|
+
Solenoid_thick_track_single_particle(part, length, ks);
|
33
|
+
//end_per_particle_block
|
34
|
+
}
|
35
|
+
}
|
36
|
+
|
37
|
+
|
38
|
+
/*gpufun*/
|
39
|
+
void Solenoid_thin_track_single_particle(
|
40
|
+
LocalParticle* part,
|
41
|
+
double length,
|
42
|
+
double ks,
|
43
|
+
double ksi
|
44
|
+
) {
|
45
|
+
const double sk = ks / 2; // todo?: flip sign to change beam direction
|
46
|
+
const double skl = ksi / 2;
|
47
|
+
const double beta0 = LocalParticle_get_beta0(part);
|
48
|
+
|
49
|
+
// Particle coordinates
|
50
|
+
const double x = LocalParticle_get_x(part);
|
51
|
+
const double px = LocalParticle_get_px(part);
|
52
|
+
const double y = LocalParticle_get_y(part);
|
53
|
+
const double py = LocalParticle_get_py(part);
|
54
|
+
const double t = LocalParticle_get_zeta(part) / beta0;
|
55
|
+
const double pt = LocalParticle_get_ptau(part);
|
56
|
+
const double delta = LocalParticle_get_delta(part);
|
57
|
+
|
58
|
+
// Useful quantities
|
59
|
+
const double psigf = pt / beta0;
|
60
|
+
const double betas = beta0;
|
61
|
+
|
62
|
+
const double onedp = 1 + delta;
|
63
|
+
const double fppsig = (1 + (betas * betas) * psigf) / onedp;
|
64
|
+
|
65
|
+
// Set up C, S, Q, R, Z
|
66
|
+
const double cosTh = cos(skl / onedp);
|
67
|
+
const double sinTh = sin(skl / onedp);
|
68
|
+
const double Q = -skl * sk / onedp;
|
69
|
+
const double Z = fppsig / (onedp * onedp) * skl;
|
70
|
+
const double R = Z * sk;
|
71
|
+
|
72
|
+
const double pxf = px + x * Q;
|
73
|
+
const double pyf = py + y * Q;
|
74
|
+
const double sigf = t * betas - 0.5 * (x * x + y * y) * R;
|
75
|
+
|
76
|
+
// Final angles after solenoid
|
77
|
+
const double pxf_ = pxf * cosTh + pyf * sinTh;
|
78
|
+
const double pyf_ = -pxf * sinTh + pyf * cosTh;
|
79
|
+
|
80
|
+
// Calculate new coordinates
|
81
|
+
const double new_x = x * cosTh + y * sinTh;
|
82
|
+
const double new_px = pxf_;
|
83
|
+
const double new_y = -x * sinTh + y * cosTh;
|
84
|
+
const double new_py = pyf_;
|
85
|
+
const double new_zeta = sigf + (x * new_py - y * new_px) * Z;
|
86
|
+
|
87
|
+
LocalParticle_set_x(part, new_x);
|
88
|
+
LocalParticle_set_px(part, new_px);
|
89
|
+
LocalParticle_set_y(part, new_y);
|
90
|
+
LocalParticle_set_py(part, new_py);
|
91
|
+
LocalParticle_set_zeta(part, new_zeta);
|
92
|
+
}
|
93
|
+
|
94
|
+
|
95
|
+
/*gpufun*/
|
96
|
+
void Solenoid_thick_track_single_particle(
|
97
|
+
LocalParticle* part,
|
98
|
+
double length,
|
99
|
+
double ks
|
100
|
+
) {
|
101
|
+
const double sk = ks / 2; // todo?: flip sign to change beam direction
|
102
|
+
|
103
|
+
if (IS_ZERO(sk)) {
|
104
|
+
Drift_single_particle(part, length);
|
105
|
+
return;
|
106
|
+
}
|
107
|
+
|
108
|
+
const double skl = sk * length;
|
109
|
+
|
110
|
+
// Particle coordinates
|
111
|
+
const double x = LocalParticle_get_x(part);
|
112
|
+
const double px = LocalParticle_get_px(part);
|
113
|
+
const double y = LocalParticle_get_y(part);
|
114
|
+
const double py = LocalParticle_get_py(part);
|
115
|
+
const double delta = LocalParticle_get_delta(part);
|
116
|
+
const double rvv = LocalParticle_get_rvv(part);
|
117
|
+
|
118
|
+
// set up constants
|
119
|
+
const double pk1 = px + sk * y;
|
120
|
+
const double pk2 = py - sk * x;
|
121
|
+
const double ptr2 = pk1 * pk1 + pk2 * pk2;
|
122
|
+
const double one_plus_delta = 1 + delta;
|
123
|
+
const double one_plus_delta_sq = one_plus_delta * one_plus_delta;
|
124
|
+
const double pz = sqrt(one_plus_delta_sq - ptr2);
|
125
|
+
|
126
|
+
// set up constants
|
127
|
+
const double cosTh = cos(skl / pz);
|
128
|
+
const double sinTh = sin(skl / pz);
|
129
|
+
|
130
|
+
const double si = sin(skl / pz) / sk;
|
131
|
+
const double rps[4] = {
|
132
|
+
cosTh * x + sinTh * y,
|
133
|
+
cosTh * px + sinTh * py,
|
134
|
+
cosTh * y - sinTh * x,
|
135
|
+
cosTh * py - sinTh * px
|
136
|
+
};
|
137
|
+
const double new_x = cosTh * rps[0] + si * rps[1];
|
138
|
+
const double new_px = cosTh * rps[1] - sk * sinTh * rps[0];
|
139
|
+
const double new_y = cosTh * rps[2] + si * rps[3];
|
140
|
+
const double new_py = cosTh * rps[3] - sk * sinTh * rps[2];
|
141
|
+
const double add_to_zeta = length * (1 - one_plus_delta / (pz * rvv));
|
142
|
+
|
143
|
+
LocalParticle_set_x(part, new_x);
|
144
|
+
LocalParticle_set_px(part, new_px);
|
145
|
+
LocalParticle_set_y(part, new_y);
|
146
|
+
LocalParticle_set_py(part, new_py);
|
147
|
+
LocalParticle_add_to_zeta(part, add_to_zeta);
|
148
|
+
LocalParticle_add_to_s(part, length);
|
149
|
+
}
|
150
|
+
|
151
|
+
#endif // XTRACK_SOLENOID_H
|
@@ -0,0 +1,382 @@
|
|
1
|
+
import numpy as np
|
2
|
+
import xobjects as xo
|
3
|
+
import xtrack as xt
|
4
|
+
|
5
|
+
class LinearRescale():
|
6
|
+
|
7
|
+
def __init__(self, knob_name, v0, dv):
|
8
|
+
self.knob_name = knob_name
|
9
|
+
self.v0 = v0
|
10
|
+
self.dv = dv
|
11
|
+
|
12
|
+
def _footprint_with_linear_rescale(linear_rescale_on_knobs, line,
|
13
|
+
freeze_longitudinal=False,
|
14
|
+
delta0=None, zeta0=None,
|
15
|
+
kwargs={}):
|
16
|
+
|
17
|
+
if isinstance (linear_rescale_on_knobs, LinearRescale):
|
18
|
+
linear_rescale_on_knobs = [linear_rescale_on_knobs]
|
19
|
+
|
20
|
+
assert len(linear_rescale_on_knobs) == 1, (
|
21
|
+
'Only one linear rescale is supported for now')
|
22
|
+
|
23
|
+
knobs_0 = {}
|
24
|
+
for rr in linear_rescale_on_knobs:
|
25
|
+
nn = rr.knob_name
|
26
|
+
v0 = rr.v0
|
27
|
+
knobs_0[nn] = v0
|
28
|
+
|
29
|
+
with xt._temp_knobs(line, knobs_0):
|
30
|
+
fp = line.get_footprint(
|
31
|
+
freeze_longitudinal=freeze_longitudinal,
|
32
|
+
delta0=delta0, zeta0=zeta0, **kwargs)
|
33
|
+
|
34
|
+
qx0 = fp.qx
|
35
|
+
qy0 = fp.qy
|
36
|
+
|
37
|
+
for rr in linear_rescale_on_knobs:
|
38
|
+
nn = rr.knob_name
|
39
|
+
v0 = rr.v0
|
40
|
+
dv = rr.dv
|
41
|
+
|
42
|
+
knobs_1 = knobs_0.copy()
|
43
|
+
knobs_1[nn] = v0 + dv
|
44
|
+
|
45
|
+
with xt._temp_knobs(line, knobs_1):
|
46
|
+
fp1 = line.get_footprint(freeze_longitudinal=freeze_longitudinal,
|
47
|
+
delta0=delta0, zeta0=zeta0, **kwargs)
|
48
|
+
delta_qx = (fp1.qx - qx0) / dv * (line.vars[nn]._value - v0)
|
49
|
+
delta_qy = (fp1.qy - qy0) / dv * (line.vars[nn]._value - v0)
|
50
|
+
|
51
|
+
fp.qx += delta_qx
|
52
|
+
fp.qy += delta_qy
|
53
|
+
|
54
|
+
return fp
|
55
|
+
|
56
|
+
class Footprint():
|
57
|
+
|
58
|
+
def __init__(self, nemitt_x=None, nemitt_y=None, n_turns=256, n_fft=2**18,
|
59
|
+
mode='polar', r_range=None, theta_range=None, n_r=None, n_theta=None,
|
60
|
+
x_norm_range=None, y_norm_range=None, n_x_norm=None, n_y_norm=None,
|
61
|
+
keep_fft=False, keep_tracking_data=False,
|
62
|
+
auto_to_numpy=True,fft_chunk_size=200
|
63
|
+
):
|
64
|
+
|
65
|
+
assert nemitt_x is not None and nemitt_y is not None, (
|
66
|
+
'nemitt_x and nemitt_y must be provided')
|
67
|
+
self.mode = mode
|
68
|
+
self.auto_to_numpy = auto_to_numpy
|
69
|
+
self.n_turns = n_turns
|
70
|
+
self.n_fft = n_fft
|
71
|
+
self.fft_chunk_size = fft_chunk_size
|
72
|
+
self.keep_fft = keep_fft
|
73
|
+
self.keep_tracking_data = keep_tracking_data
|
74
|
+
|
75
|
+
self.nemitt_x = nemitt_x
|
76
|
+
self.nemitt_y = nemitt_y
|
77
|
+
|
78
|
+
assert mode in ['polar', 'uniform_action_grid'], (
|
79
|
+
'mode must be either polar or uniform_action_grid')
|
80
|
+
|
81
|
+
if mode == 'polar':
|
82
|
+
|
83
|
+
assert x_norm_range is None and y_norm_range is None, (
|
84
|
+
'x_norm_range and y_norm_range must be None for mode polar')
|
85
|
+
assert n_x_norm is None and n_y_norm is None, (
|
86
|
+
'n_x_norm and n_y_norm must be None for mode polar')
|
87
|
+
|
88
|
+
if r_range is None:
|
89
|
+
r_range = (0.1, 6)
|
90
|
+
if theta_range is None:
|
91
|
+
theta_range = (0.05, np.pi/2-0.05)
|
92
|
+
if n_r is None:
|
93
|
+
n_r = 10
|
94
|
+
if n_theta is None:
|
95
|
+
n_theta = 10
|
96
|
+
|
97
|
+
self.r_range = r_range
|
98
|
+
self.theta_range = theta_range
|
99
|
+
self.n_r = n_r
|
100
|
+
self.n_theta = n_theta
|
101
|
+
|
102
|
+
self.r_grid = np.linspace(*r_range, n_r)
|
103
|
+
self.theta_grid = np.linspace(*theta_range, n_theta)
|
104
|
+
self.R_2d, self.Theta_2d = np.meshgrid(self.r_grid, self.theta_grid)
|
105
|
+
|
106
|
+
self.x_norm_2d = self.R_2d * np.cos(self.Theta_2d)
|
107
|
+
self.y_norm_2d = self.R_2d * np.sin(self.Theta_2d)
|
108
|
+
|
109
|
+
elif mode == 'uniform_action_grid':
|
110
|
+
|
111
|
+
assert r_range is None and theta_range is None, (
|
112
|
+
'r_range and theta_range must be None for mode uniform_action_grid')
|
113
|
+
assert n_r is None and n_theta is None, (
|
114
|
+
'n_r and n_theta must be None for mode uniform_action_grid')
|
115
|
+
|
116
|
+
if x_norm_range is None:
|
117
|
+
x_norm_range = (0.1, 6)
|
118
|
+
if y_norm_range is None:
|
119
|
+
y_norm_range = (0.1, 6)
|
120
|
+
if n_x_norm is None:
|
121
|
+
n_x_norm = 10
|
122
|
+
if n_y_norm is None:
|
123
|
+
n_y_norm = 10
|
124
|
+
|
125
|
+
Jx_min = nemitt_x * x_norm_range[0]**2 / 2
|
126
|
+
Jx_max = nemitt_x * x_norm_range[1]**2 / 2
|
127
|
+
Jy_min = nemitt_y * y_norm_range[0]**2 / 2
|
128
|
+
Jy_max = nemitt_y * y_norm_range[1]**2 / 2
|
129
|
+
|
130
|
+
self.Jx_grid = np.linspace(Jx_min, Jx_max, n_x_norm)
|
131
|
+
self.Jy_grid = np.linspace(Jy_min, Jy_max, n_y_norm)
|
132
|
+
|
133
|
+
self.Jx_2d, self.Jy_2d = np.meshgrid(self.Jx_grid, self.Jy_grid)
|
134
|
+
|
135
|
+
self.x_norm_2d = np.sqrt(2 * self.Jx_2d / nemitt_x)
|
136
|
+
self.y_norm_2d = np.sqrt(2 * self.Jy_2d / nemitt_y)
|
137
|
+
|
138
|
+
def _compute_footprint(self, line, freeze_longitudinal=False,
|
139
|
+
delta0=None, zeta0=None):
|
140
|
+
|
141
|
+
if freeze_longitudinal is None:
|
142
|
+
# In future we could detect if the line has frozen longitudinal plane
|
143
|
+
freeze_longitudinal = False
|
144
|
+
|
145
|
+
nplike_lib = line._context.nplike_lib
|
146
|
+
|
147
|
+
particles = line.build_particles(
|
148
|
+
x_norm=self.x_norm_2d.flatten(), y_norm=self.y_norm_2d.flatten(),
|
149
|
+
nemitt_x=self.nemitt_x, nemitt_y=self.nemitt_y,
|
150
|
+
zeta=zeta0, delta=delta0,
|
151
|
+
freeze_longitudinal=freeze_longitudinal,
|
152
|
+
method={True: '4d', False: '6d'}[freeze_longitudinal]
|
153
|
+
)
|
154
|
+
|
155
|
+
print('Tracking particles for footprint...')
|
156
|
+
line.track(particles, num_turns=self.n_turns, turn_by_turn_monitor=True,
|
157
|
+
freeze_longitudinal=freeze_longitudinal)
|
158
|
+
print('Done tracking.')
|
159
|
+
|
160
|
+
ctx2np = line._context.nparray_from_context_array
|
161
|
+
assert np.all(ctx2np(particles.state == 1)), (
|
162
|
+
'Some particles were lost during tracking')
|
163
|
+
mon = line.record_last_track
|
164
|
+
mon.auto_to_numpy = False
|
165
|
+
|
166
|
+
if isinstance(line._context, xo.ContextPyopencl):
|
167
|
+
raise NotImplementedError(
|
168
|
+
'Footprint calculation with Pyopencl not supported yet. '
|
169
|
+
'Let us know if you need this feature.')
|
170
|
+
# Could be implemented using xobject fft
|
171
|
+
|
172
|
+
x_noCO = mon.x - nplike_lib.atleast_2d(mon.x.mean(axis=1)).T
|
173
|
+
y_noCO = mon.y - nplike_lib.atleast_2d(mon.y.mean(axis=1)).T
|
174
|
+
|
175
|
+
freq_axis = nplike_lib.fft.rfftfreq(self.n_fft)
|
176
|
+
|
177
|
+
npart = nplike_lib.shape(x_noCO)[0]
|
178
|
+
self.qx = nplike_lib.zeros(npart,dtype=float)
|
179
|
+
self.qy = nplike_lib.zeros(npart,dtype=float)
|
180
|
+
|
181
|
+
if self.keep_fft:
|
182
|
+
self.fft_x = nplike_lib.zeros((npart,len(freq_axis)),dtype=complex)
|
183
|
+
self.fft_y = nplike_lib.zeros((npart,len(freq_axis)),dtype=complex)
|
184
|
+
|
185
|
+
# Compute in chunks
|
186
|
+
iStart = 0
|
187
|
+
while iStart < npart:
|
188
|
+
iEnd = iStart + self.fft_chunk_size
|
189
|
+
if iEnd > npart:
|
190
|
+
iEnd = npart
|
191
|
+
fft_x = nplike_lib.fft.rfft(x_noCO[iStart:iEnd,:], n=self.n_fft)
|
192
|
+
fft_y = nplike_lib.fft.rfft(y_noCO[iStart:iEnd,:], n=self.n_fft)
|
193
|
+
if self.keep_fft:
|
194
|
+
self.fft_x[iStart:iEnd,:] = fft_x
|
195
|
+
self.fft_y[iStart:iEnd,:] = fft_y
|
196
|
+
qx = freq_axis[nplike_lib.argmax(nplike_lib.abs(fft_x), axis=1)]
|
197
|
+
qy = freq_axis[nplike_lib.argmax(nplike_lib.abs(fft_y), axis=1)]
|
198
|
+
self.qx[iStart:iEnd] = qx
|
199
|
+
self.qy[iStart:iEnd] = qy
|
200
|
+
iStart += self.fft_chunk_size
|
201
|
+
|
202
|
+
self.qx = nplike_lib.reshape(self.qx, self.x_norm_2d.shape)
|
203
|
+
self.qy = nplike_lib.reshape(self.qy, self.y_norm_2d.shape)
|
204
|
+
|
205
|
+
if self.auto_to_numpy:
|
206
|
+
ctx2np = line._context.nparray_from_context_array
|
207
|
+
self.qx = ctx2np(self.qx)
|
208
|
+
self.qy = ctx2np(self.qy)
|
209
|
+
if self.keep_fft:
|
210
|
+
self.fft_x = ctx2np(self.fft_x)
|
211
|
+
self.fft_y = ctx2np(self.fft_y)
|
212
|
+
|
213
|
+
if self.keep_tracking_data:
|
214
|
+
self.tracking_data = mon
|
215
|
+
|
216
|
+
print ('Done computing footprint.')
|
217
|
+
|
218
|
+
def _compute_tune_shift(self,_context,J1_2d,J1_grid,J2_2d,J2_grid,q,coherent_tune,epsilon):
|
219
|
+
nplike_lib = _context.nplike_lib
|
220
|
+
ctx2np = _context.nparray_from_context_array
|
221
|
+
np2ctx = _context.nparray_to_context_array
|
222
|
+
|
223
|
+
integrand = -J1_2d*nplike_lib.exp(-J1_2d-J2_2d) / (coherent_tune - q + epsilon*1j)
|
224
|
+
tune_shift = ctx2np(-1.0/nplike_lib.trapz(J2_grid,nplike_lib.trapz(J1_grid,integrand,1),0))
|
225
|
+
return tune_shift
|
226
|
+
|
227
|
+
def _compute_tune_shift_adaptive_epsilon(self,_context,J1_2d,J1_grid,J2_2d,J2_grid,q,coherent_tune,
|
228
|
+
epsilon0,epsilon_factor,epsilon_rel_tol,max_iter,min_epsilon):
|
229
|
+
tune_shift = self._compute_tune_shift(_context,J1_2d,J1_grid,J2_2d,J2_grid,q,coherent_tune,epsilon0)
|
230
|
+
if epsilon_factor > 0.0:
|
231
|
+
epsilon_ref = epsilon0
|
232
|
+
epsilon = np.abs(np.imag(tune_shift)*epsilon_factor)
|
233
|
+
if epsilon < min_epsilon:
|
234
|
+
epsilon = min_epsilon
|
235
|
+
count = 0
|
236
|
+
while np.abs(1-epsilon/epsilon_ref) > epsilon_rel_tol and count < max_iter and epsilon >= min_epsilon:
|
237
|
+
tune_shift = self._compute_tune_shift(_context,J1_2d,J1_grid,J2_2d,J2_grid,q,coherent_tune,epsilon)
|
238
|
+
epsilon_ref = epsilon
|
239
|
+
epsilon = np.abs(np.imag(tune_shift)*epsilon_factor)
|
240
|
+
count += 1
|
241
|
+
return tune_shift
|
242
|
+
|
243
|
+
def get_stability_diagram(
|
244
|
+
self,
|
245
|
+
_context=None,
|
246
|
+
n_points_stabiliy_diagram=100,
|
247
|
+
epsilon0=1e-5,
|
248
|
+
epsilon_factor=0.1,
|
249
|
+
epsilon_rel_tol=0.1,
|
250
|
+
max_iter=10,
|
251
|
+
min_epsilon=1e-6,
|
252
|
+
n_points_interpolate=1000,
|
253
|
+
):
|
254
|
+
"""
|
255
|
+
Compute the stability diagram by evaluating the dispersion integral from [1]
|
256
|
+
numerically for a set of complex tune shifts with vanishing imaginary part.
|
257
|
+
By convention the imaginary part is positive.
|
258
|
+
|
259
|
+
Parameters
|
260
|
+
----------
|
261
|
+
_context:
|
262
|
+
n_points_stabiliy_diagram: scalar(int)
|
263
|
+
Number of times that the dispersion integral will be solved,
|
264
|
+
each yielding a point on the output stability diagram
|
265
|
+
epsilon0: scalar(float)
|
266
|
+
vanishing imaginary part of the tune shift
|
267
|
+
epsilon_factor: scalar(float)
|
268
|
+
if larger than 0, an adaptive algorithm will be used to adjust
|
269
|
+
epsilon between epsilon0 and epsilon_min using relative varitions
|
270
|
+
in the order of the epsilon_factor
|
271
|
+
epsilon_rel_tol: scalar(float)
|
272
|
+
Stop the iterative algorithm if the relative change of
|
273
|
+
epilson is smaller than epsilon_rel_tol
|
274
|
+
max_iter: scalar(int)
|
275
|
+
Stop the iterative algorithm if the the number of iterations
|
276
|
+
reached max_iter
|
277
|
+
min_epsilon: scalar(float)
|
278
|
+
Stop the iterative algorithm if the epsilon is smaller than
|
279
|
+
min_epsilon
|
280
|
+
n_points_interpolate: scalar(int)
|
281
|
+
Perform the numerical integration on a grid finer than the footprint
|
282
|
+
using linear interpolation
|
283
|
+
|
284
|
+
Returns
|
285
|
+
-------
|
286
|
+
tune_shifts_x: array_like(complex)
|
287
|
+
Horizontal stability diagram
|
288
|
+
tune_shifts_y: array_like(complex)
|
289
|
+
Vertical stability diagram
|
290
|
+
|
291
|
+
References
|
292
|
+
----------
|
293
|
+
[1] https://cds.cern.ch/record/318826
|
294
|
+
[2] https://doi.org/10.1103/PhysRevSTAB.17.111002
|
295
|
+
"""
|
296
|
+
if _context == None:
|
297
|
+
_context = xo.ContextCpu()
|
298
|
+
nplike_lib = _context.nplike_lib
|
299
|
+
splike_lib = _context.splike_lib
|
300
|
+
ctx2np = _context.nparray_from_context_array
|
301
|
+
np2ctx = _context.nparray_to_context_array
|
302
|
+
|
303
|
+
Jx_2d = np2ctx(self.Jx_2d / self.nemitt_x)
|
304
|
+
Jx_grid = np2ctx(self.Jx_grid / self.nemitt_x)
|
305
|
+
Jy_2d = np2ctx(self.Jy_2d / self.nemitt_y)
|
306
|
+
Jy_grid = np2ctx(self.Jy_grid / self.nemitt_y)
|
307
|
+
qx = np2ctx(self.qx)
|
308
|
+
qy = np2ctx(self.qy)
|
309
|
+
|
310
|
+
if n_points_interpolate > len(Jx_grid) or n_points_interpolate > len(Jy_grid):
|
311
|
+
interpolator_x = splike_lib.interpolate.RegularGridInterpolator(
|
312
|
+
points=[Jy_grid, Jx_grid], values=qx, bounds_error=True, fill_value=None
|
313
|
+
)
|
314
|
+
interpolator_y = splike_lib.interpolate.RegularGridInterpolator(
|
315
|
+
points=[Jy_grid, Jx_grid], values=qy, bounds_error=True, fill_value=None
|
316
|
+
)
|
317
|
+
Jx_grid = nplike_lib.linspace(Jx_grid[0], Jx_grid[-1], n_points_interpolate)
|
318
|
+
Jy_grid = nplike_lib.linspace(Jy_grid[0], Jy_grid[-1], n_points_interpolate)
|
319
|
+
Jx_2d, Jy_2d = nplike_lib.meshgrid(Jx_grid, Jy_grid)
|
320
|
+
qx = interpolator_x((Jy_2d, Jx_2d))
|
321
|
+
qy = interpolator_y((Jy_2d, Jx_2d))
|
322
|
+
|
323
|
+
coherent_tunes_x = np.linspace(
|
324
|
+
np.min(self.qx), np.max(self.qx), n_points_stabiliy_diagram
|
325
|
+
)
|
326
|
+
coherent_tunes_y = np.linspace(
|
327
|
+
np.min(self.qy), np.max(self.qy), n_points_stabiliy_diagram
|
328
|
+
)
|
329
|
+
tune_shifts_x = np.zeros_like(coherent_tunes_x, dtype=complex)
|
330
|
+
tune_shifts_y = np.zeros_like(coherent_tunes_y, dtype=complex)
|
331
|
+
for i in range(n_points_stabiliy_diagram):
|
332
|
+
tune_shifts_x[i] = self._compute_tune_shift_adaptive_epsilon(
|
333
|
+
_context=_context,
|
334
|
+
J1_2d=Jx_2d,
|
335
|
+
J1_grid=Jx_grid,
|
336
|
+
J2_2d=Jy_2d,
|
337
|
+
J2_grid=Jy_grid,
|
338
|
+
q=qx,
|
339
|
+
coherent_tune=coherent_tunes_x[i],
|
340
|
+
epsilon0=epsilon0,
|
341
|
+
epsilon_factor=epsilon_factor,
|
342
|
+
epsilon_rel_tol=epsilon_rel_tol,
|
343
|
+
max_iter=max_iter,
|
344
|
+
min_epsilon=min_epsilon,
|
345
|
+
)
|
346
|
+
tune_shifts_y[i] = self._compute_tune_shift_adaptive_epsilon(
|
347
|
+
_context=_context,
|
348
|
+
J1_2d=Jy_2d,
|
349
|
+
J1_grid=Jy_grid,
|
350
|
+
J2_2d=Jx_2d,
|
351
|
+
J2_grid=Jx_grid,
|
352
|
+
q=qy,
|
353
|
+
coherent_tune=coherent_tunes_y[i],
|
354
|
+
epsilon0=epsilon0,
|
355
|
+
epsilon_factor=epsilon_factor,
|
356
|
+
epsilon_rel_tol=epsilon_rel_tol,
|
357
|
+
max_iter=max_iter,
|
358
|
+
min_epsilon=min_epsilon,
|
359
|
+
)
|
360
|
+
return tune_shifts_x, tune_shifts_y
|
361
|
+
|
362
|
+
def plot(self, ax=None, **kwargs):
|
363
|
+
import matplotlib.pyplot as plt
|
364
|
+
|
365
|
+
if ax is None:
|
366
|
+
ax = plt.gca()
|
367
|
+
|
368
|
+
if 'color' not in kwargs:
|
369
|
+
kwargs['color'] = 'k'
|
370
|
+
|
371
|
+
labels = [None] * self.qx.shape[1]
|
372
|
+
|
373
|
+
if 'label' in kwargs:
|
374
|
+
label_str = kwargs['label']
|
375
|
+
kwargs.pop('label')
|
376
|
+
labels[0] = label_str
|
377
|
+
|
378
|
+
ax.plot(self.qx, self.qy, label=labels, **kwargs)
|
379
|
+
ax.plot(self.qx.T, self.qy.T, **kwargs)
|
380
|
+
|
381
|
+
ax.set_xlabel(r'$q_x$')
|
382
|
+
ax.set_ylabel(r'$q_y$')
|