Skip to content

Commit

Permalink
Merge pull request #16 from PyCOMPLETE/hotfix/detuning-corrected
Browse files Browse the repository at this point in the history
Hotfix: detuners did not use relative phase advances accQ_x, accQ_y.

This hotfix makes the detuners use the relative bare betatron
phase advance per segment instead of the averaged segment_length.

This is important if accQ_x and accQ_y in the TransverseMap
during setup are not given as scalar values of the betatron tune
(which ends in the smooth approximation) but instead are taken as
varying arrays e.g. from real TWISS lattices.

RFQ, Detuners and TransverseTrackings have been adapted in both
Python and Cython versions. Also the tests have been adapted
both in interactive-tests and unittests.
  • Loading branch information
aoeftiger committed Jul 13, 2015
2 parents 0dd13e2 + 4810db0 commit 700d026
Show file tree
Hide file tree
Showing 15 changed files with 985 additions and 454 deletions.
78 changes: 44 additions & 34 deletions rfq/rfq.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ kick, i.e. a change in a particle's normalized momentum dp. For model
(II), the incoherent betatron detuning is not applied directly, but is
a consequence of the change in momenta xp and yp.
@author Michael Schenk
@author Michael Schenk, Adrian Oeftiger
@date July, 10th 2014
@brief Cython implementation of a pillbox cavity RF quadrupole for
Landau damping.
Expand All @@ -45,15 +45,16 @@ from ..trackers.detuners import DetunerCollection


class RFQTransverseDetuner(DetunerCollection):
""" Collection class to contain/manage the segment-wise defined
"""Collection class to contain/manage the segment-wise defined
RFQ elements RFQTransverseDetunerSegment acting on the
betatron tunes (detuner model of the RFQ). This is a pure
Python class and it derives from the DetunerCollection class
defined in the module PyHEADTAIL.trackers.detuners. """
defined in the module PyHEADTAIL.trackers.detuners.
"""

def __init__(self, v_2, omega, phi_0, beta_x_RFQ, beta_y_RFQ,
n_threads=1):
""" An RFQ element is fully characterized by the parameters
"""An RFQ element is fully characterized by the parameters
v_2: quadrupolar expansion coefficient of the accelerating
voltage (~strength of the RFQ), in [V/m^2]. One-turn
value.
Expand All @@ -67,7 +68,8 @@ class RFQTransverseDetuner(DetunerCollection):
n_threads defines the number of threads to be used to execute
the for-loop on the number of particles with cython OpenMP. It
is set to 1 by default. """
is set to 1 by default.
"""
self.v_2 = v_2
self.omega = omega
self.phi_0 = phi_0
Expand All @@ -78,46 +80,49 @@ class RFQTransverseDetuner(DetunerCollection):
self.n_threads = n_threads
self.segment_detuners = []

def generate_segment_detuner(self, segment_length, **kwargs):
""" Instantiates a RFQTransverseSegmentDetuner for the
specified segment of the accelerator ring. Note that the
segment_length is given as a relative value, i.e. in units
of accelerator circumference. It scales the one turn value
for the detuning strength proportionally to the segment
length. The method is called by the TransverseMap object
which manages the creation of a detuner for every defined
segment. """
def generate_segment_detuner(self, dmu_x, dmu_y, **kwargs):
"""Instantiate a RFQTransverseSegmentDetuner for the
specified segment of the accelerator ring.
Note that the bare betatron
phase advances over the current segment, dmu_x and dmu_y, are
given as relative values, i.e. in units of the overall phase
advance around the whole accelerator (the betatron tune).
The method is called by the TransverseMap object which manages
the creation of a detuner for every defined segment.
"""
dapp_xz = self.beta_x_RFQ * self.v_2 * e / (2.*np.pi*self.omega)
dapp_yz = -self.beta_y_RFQ * self.v_2 * e / (2.*np.pi*self.omega)
dapp_xz *= segment_length
dapp_yz *= segment_length
dapp_xz *= dmu_x
dapp_yz *= dmu_y

detuner = RFQTransverseDetunerSegment(
dapp_xz, dapp_yz, self.omega, self.phi_0, n_threads=self.n_threads)
self.segment_detuners.append(detuner)


cdef class RFQTransverseDetunerSegment(object):
""" Cython implementation of the RFQ element acting directly on the
particles' betatron tunes (i.e. RFQ detuner model). """
"""Cython implementation of the RFQ element acting directly on the
particles' betatron tunes (i.e. RFQ detuner model).
"""

cdef double dapp_xz, dapp_yz, omega, phi_0
cdef int n_threads

def __init__(self, dapp_xz, dapp_yz, omega, phi_0, n_threads):
""" Creates an instance of the RFQTransverseDetunerSegment
"""Creates an instance of the RFQTransverseDetunerSegment
class. The RFQ is characterized by
omega: Angular frequency of the RF wave, in [rad/s].
phi_0: Constant phase offset wrt. bunch center (z=0), in
[rad].
dapp_xz: Strength of detuning in the horizontal plane, scaled
to the relative segment length.
to the relative bare betatron phase advance in x.
dapp_yz: Strength of detuning in the vertical plane, scaled
to the relative segment length.
to the relative bare betatron phase advance in y.
n_threads defines the number of threads to be used to execute
the for-loop on the number of particles with cython OpenMP. It
is set to 1 by default. """
is set to 1 by default.
"""
self.dapp_xz = dapp_xz
self.dapp_yz = dapp_yz

Expand Down Expand Up @@ -166,16 +171,17 @@ cdef class RFQTransverseDetunerSegment(object):


cdef class RFQKick(object):
""" Cython base class to describe the RFQ element in the
"""Cython base class to describe the RFQ element in the
localized kick model for both the transverse and the
longitudinal coordinates. This class should be considered
an abstract base class and not be instantiated by the
user (note: ABCs are not yet supported in Cython). """
user (note: ABCs are not yet supported in Cython).
"""
cdef double v_2, omega, phi_0
cdef int n_threads

def __init__(self, v_2, omega, phi_0, n_threads=1):
""" An RFQ element is fully characterized by the parameters
"""An RFQ element is fully characterized by the parameters
v_2: quadrupolar expansion coefficient of the
accelerating voltage (~strength of the RFQ), in
[V/m^2].
Expand All @@ -185,7 +191,8 @@ cdef class RFQKick(object):
n_threads defines the number of threads to be used to execute
the for-loop on the number of particles with cython OpenMP. It
is set to 1 by default. """
is set to 1 by default.
"""
self.v_2 = v_2
self.omega = omega
self.phi_0 = phi_0
Expand All @@ -197,14 +204,15 @@ cdef class RFQKick(object):


cdef class RFQTransverseKick(RFQKick):
""" Cython implementation of the RFQ element acting on the
"""Cython implementation of the RFQ element acting on the
particles' transverse coordinates (i.e. localized kick
model). """
model).
"""

@cython.boundscheck(False)
@cython.cdivision(True)
def track(self, beam):
""" The formula that describes the transverse kick experienced
"""The formula that describes the transverse kick experienced
by an ultra-relativistic particle traversing the RFQ
longitudinally is based on the thin-lens approximation
\Delta p_x = -x*(2 e v_2 / omega) *
Expand All @@ -214,7 +222,8 @@ cdef class RFQTransverseKick(RFQKick):
The for loop on the number of particles can make use of cython
OpenMP with the number of threads defined by self.n_threads. It
is set to 1 by default. """
is set to 1 by default.
"""
cdef double[::1] x = beam.x
cdef double[::1] y = beam.y
cdef double[::1] z = beam.z
Expand All @@ -241,20 +250,21 @@ cdef class RFQTransverseKick(RFQKick):


cdef class RFQLongitudinalKick(RFQKick):
""" Cython implementation of the RFQ element acting on the
particles' longitudinal coordinate dp. """
"""Cython implementation of the RFQ element acting on the
particles' longitudinal coordinate dp."""

@cython.boundscheck(False)
@cython.cdivision(True)
def track(self, beam):
""" The formula used to describe the longitudinal kick is given
"""The formula used to describe the longitudinal kick is given
by
\Delta p_z = -(x^2 - y^2) (e v_2 / (beta c)) *
sin(omega z / (beta c) + phi_0).
The for loop on the number of particles can make use of cython
OpenMP with the number of threads defined by self.n_threads. It
is set to 1 by default. """
is set to 1 by default.
"""
cdef double[::1] x = beam.x
cdef double[::1] y = beam.y
cdef double[::1] z = beam.z
Expand Down
74 changes: 45 additions & 29 deletions testing/interactive-tests/DetunersCythonTest.ipynb

Large diffs are not rendered by default.

81 changes: 62 additions & 19 deletions testing/interactive-tests/DetunersTest.ipynb

Large diffs are not rendered by default.

79 changes: 49 additions & 30 deletions testing/interactive-tests/RFQTest.ipynb

Large diffs are not rendered by default.

121 changes: 104 additions & 17 deletions testing/interactive-tests/TransverseTrackingCythonTest.ipynb

Large diffs are not rendered by default.

137 changes: 108 additions & 29 deletions testing/interactive-tests/TransverseTrackingTest.ipynb

Large diffs are not rendered by default.

22 changes: 12 additions & 10 deletions testing/unittests/autoruntests/DetunersCythonTest.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

# coding: utf-8

# In[1]:

import sys, os
Expand All @@ -18,15 +20,14 @@


# In[3]:

# HELPERS
def run():
# HELPERS
def track(bunch, map_):
for i in range(n_turns):
for m in map_:
m.track(bunch)



def generate_bunch(n_macroparticles, alpha_x, alpha_y, beta_x, beta_y, alpha_0, Q_s, R):
intensity = 1.05e11
sigma_z = 0.059958
Expand All @@ -47,15 +48,17 @@ def generate_bunch(n_macroparticles, alpha_x, alpha_y, beta_x, beta_y, alpha_0,
alpha_x=alpha_x, beta_x=beta_x, epsn_x=epsn_x,
alpha_y=alpha_y, beta_y=beta_y, epsn_y=epsn_y,
beta_z=beta_z, epsn_z=epsn_z)
#print bunch.sigma_z()

return bunch


# In[4]:

# Basic parameters.
n_turns = 2
n_turns = 3
n_segments = 1
n_macroparticles = 5
n_macroparticles = 10

Q_x = 64.28
Q_y = 59.31
Expand Down Expand Up @@ -102,6 +105,7 @@ def generate_bunch(n_macroparticles, alpha_x, alpha_y, beta_x, beta_y, alpha_0,

trans_one_turn = [ m for m in trans_map ]
map_ = trans_one_turn

track(bunch, map_)


Expand All @@ -123,7 +127,7 @@ def generate_bunch(n_macroparticles, alpha_x, alpha_y, beta_x, beta_y, alpha_0,
track(bunch, map_)


# In[14]:
# In[8]:

# CASE III
# With higher order Chromaticity (python implementation)
Expand All @@ -140,11 +144,9 @@ def generate_bunch(n_macroparticles, alpha_x, alpha_y, beta_x, beta_y, alpha_0,

track(bunch, map_)

# In[ ]:


if __name__ == '__main__':
run()

# In[15]:


# In[ ]:
35 changes: 12 additions & 23 deletions testing/unittests/autoruntests/DetunersTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@
import PyHEADTAIL.particles.generators as generators


# In[24]:
# In[3]:

# HELPERS
def run():
# HELPERS
def track(bunch, map_):
for i in range(n_turns):
for m in map_:
m.track(bunch)


def generate_bunch(n_macroparticles, alpha_x, alpha_y, beta_x, beta_y, alpha_0, Q_s, R):
intensity = 1.05e11
sigma_z = 0.059958
Expand All @@ -53,12 +53,12 @@ def generate_bunch(n_macroparticles, alpha_x, alpha_y, beta_x, beta_y, alpha_0,
return bunch


# In[25]:
# In[4]:

# Basic parameters.
n_turns = 2
# Basic parameters.
n_turns = 3
n_segments = 1
n_macroparticles = 20
n_macroparticles = 10

Q_x = 64.28
Q_y = 59.31
Expand All @@ -74,7 +74,7 @@ def generate_bunch(n_macroparticles, alpha_x, alpha_y, beta_x, beta_y, alpha_0,
alpha_0 = 0.0003225


# In[26]:
# In[5]:

# Parameters for transverse map.
s = np.arange(0, n_segments + 1) * C / n_segments
Expand All @@ -88,7 +88,7 @@ def generate_bunch(n_macroparticles, alpha_x, alpha_y, beta_x, beta_y, alpha_0,
D_y = np.zeros(n_segments)


# In[27]:
# In[6]:

# CASE I
# With amplitude detuning (python implementation)
Expand All @@ -109,7 +109,7 @@ def generate_bunch(n_macroparticles, alpha_x, alpha_y, beta_x, beta_y, alpha_0,
track(bunch, map_)


# In[53]:
# In[7]:

# CASE II
# With first order Chromaticity (python implementation)
Expand All @@ -127,7 +127,7 @@ def generate_bunch(n_macroparticles, alpha_x, alpha_y, beta_x, beta_y, alpha_0,
track(bunch, map_)


# In[56]:
# In[8]:

# CASE III
# With higher order Chromaticity (python implementation)
Expand All @@ -145,21 +145,10 @@ def generate_bunch(n_macroparticles, alpha_x, alpha_y, beta_x, beta_y, alpha_0,
track(bunch, map_)


# In[58]:

# CASE IV
# detuning functions for higher order chroma.

chroma = Chromaticity(Qp_x=[6., 4e4], Qp_y=[3., 0., 2e8])
chroma.generate_segment_detuner(segment_length=1)

dp = np.linspace(-5e-4, 5e-4, 500)
# In[ ]:

dQx = chroma.segment_detuners[0].calc_detuning_x(dp)
dQy = chroma.segment_detuners[0].calc_detuning_y(dp)

if __name__ == '__main__':
run()


# In[ ]:
Loading

0 comments on commit 700d026

Please sign in to comment.