Collimation
Loss location refinement
In Xtrack simulations particles are lost at defined aperture elements (e.g.
xtrack.LimitRect
, xtrack.LimitEllipse
, xtrack.LimitRectEllipse
,
xtrack.LimitPolygon
). A more accurate estimate of the loss locations can be
obtained after the tracking is finished using the
xtrack.LossLocationRefinement
tool . The tool builds
an interpolated aperture model between the aperture elements and backtracks the
particles in order to identify the impact point. The following example illustrates
how to use this feature.
See also: xtrack.LossLocationRefinement
import numpy as np
import xtrack as xt
import xobjects as xo
###################
# Build test line #
###################
ctx = xo.context_default
buf = ctx.new_buffer()
# We build a test line having two aperture elements which are shifted and
# rotated w.r.t. the accelerator reference frame.
# Define aper_0
aper_0 = xt.LimitEllipse(_buffer=buf, a=2e-2, b=1e-2)
shift_aper_0 = (1e-2, 0.5e-2)
rot_deg_aper_0 = 10.
# Define aper_1
aper_1 = xt.LimitRect(_buffer=buf, min_x=-1e-2, max_x=1e-2,
min_y=-2e-2, max_y=2e-2)
shift_aper_1 = (-5e-3, 1e-2)
rot_deg_aper_1 = 10.
aper_1.shift_x = shift_aper_1[0]
aper_1.shift_y = shift_aper_1[1]
aper_1.rot_s_rad = np.deg2rad(rot_deg_aper_1)
# aper_0_sandwitch
line_aper_0 = xt.Line(
elements=[xt.XYShift(_buffer=buf, dx=shift_aper_0[0], dy=shift_aper_0[1]),
xt.SRotation(_buffer=buf, angle=rot_deg_aper_0),
aper_0,
xt.Multipole(_buffer=buf, knl=[0.001]),
xt.SRotation(_buffer=buf, angle=-rot_deg_aper_0),
xt.XYShift(_buffer=buf, dx=-shift_aper_0[0], dy=-shift_aper_0[1])])
line_aper_0.build_tracker(_buffer=buf)
# aper_1_sandwitch
line_aper_1 = xt.Line(
elements=[aper_1,
xt.Multipole(_buffer=buf, knl=[0.001])
])
line_aper_1.build_tracker(_buffer=buf)
#################
# Build tracker #
#################
line=xt.Line(
elements = ((xt.Drift(_buffer=buf, length=0.5),)
+ line_aper_0.elements
+ (xt.Drift(_buffer=buf, length=1),
xt.Drift(_buffer=buf, length=1),
xt.Drift(_buffer=buf, length=1.),)
+ line_aper_1.elements))
line.build_tracker(_buffer=buf)
num_elements = len(line.element_names)
# Generate test particles
particles = xt.Particles(_context=ctx,
px=np.random.uniform(-0.01, 0.01, 10000),
py=np.random.uniform(-0.01, 0.01, 10000))
#########
# Track #
#########
line.track(particles)
########################
# Refine loss location #
########################
loss_loc_refinement = xt.LossLocationRefinement(line,
n_theta = 360, # Angular resolution in the polygonal approximation of the aperture
r_max = 0.5, # Maximum transverse aperture in m
dr = 50e-6, # Transverse loss refinement accuracy [m]
ds = 0.1, # Longitudinal loss refinement accuracy [m]
save_refine_lines=True # Diagnostics flag
)
loss_loc_refinement.refine_loss_location(particles)
# Complete source: xtrack/examples/collimation/001_loss_location_refinement.py
Beam interaction (generation of secondary particles)
Xtrack includes an interface to ease the modeling of beam-matter interaction (collimators, beam-gas, collisions with another beam), including the loss of the impacting particles and the production of secondary particles, which need to be tracked together with the surviving beam. Such interface can be used to create a link with other programs for the modeling of these effects, e.g. GEANT, FLUKA, K2, GuineaPig.
The interaction is defined as an object that provides a .interact(particles)
method, which sets to zero or negative the state
flag for the particles that are lost and
returns a dictionary with the coordinates of the secondary particles that are
emitted. The interaction process is embedded in one or multiple
xtrack.BeamInteraction
beam elements that can be included in Xtrack line.
This is illustrated by the following example:
import numpy as np
import xtrack as xt
######################################
# Create a dummy collimation process #
######################################
class DummyInteractionProcess:
'''
I kill some particles. I kick some others by an given angle
and I generate some secondaries with the opposite angles.
'''
def __init__(self, fraction_lost, fraction_secondary, length, kick_x):
self.fraction_lost = fraction_lost
self.fraction_secondary = fraction_secondary
self.kick_x = kick_x
self.length = length
self.drift = xt.Drift(length=self.length)
def interact(self, particles):
self.drift.track(particles)
n_part = particles._num_active_particles
# Kill some particles
mask_kill = np.random.uniform(size=n_part) < self.fraction_lost
particles.state[:n_part][mask_kill] = -1 # special flag`
# Generate some more particles
mask_secondary = np.random.uniform(size=n_part) < self.fraction_secondary
n_products = np.sum(mask_secondary)
if n_products>0:
products = {
's': particles.s[:n_part][mask_secondary],
'x': particles.x[:n_part][mask_secondary],
'px': particles.px[:n_part][mask_secondary] + self.kick_x,
'y': particles.y[:n_part][mask_secondary],
'py': particles.py[:n_part][mask_secondary],
'zeta': particles.zeta[:n_part][mask_secondary],
'delta': particles.delta[:n_part][mask_secondary],
'mass_ratio': particles.x[:n_part][mask_secondary] *0 + 1.,
'charge_ratio': particles.x[:n_part][mask_secondary] *0 + 1.,
'parent_particle_id': particles.particle_id[:n_part][mask_secondary],
'at_element': particles.at_element[:n_part][mask_secondary],
'at_turn': particles.at_turn[:n_part][mask_secondary],
}
else:
products = None
return products
############################################################
# Create a beam interaction from the process defined above #
############################################################
interaction_process=DummyInteractionProcess(length=1., kick_x=4e-3,
fraction_lost=0.0,
fraction_secondary=0.2)
collimator = xt.BeamInteraction(length=interaction_process.length,
interaction_process=interaction_process)
########################################################
# Create a line including the collimator defined above #
########################################################
line = xt.Line(elements=[
xt.Multipole(knl=[0,0]),
xt.LimitEllipse(a=2e-2, b=2e-2),
xt.Drift(length=1.),
xt.Multipole(knl=[0,0]),
xt.LimitEllipse(a=2e-2, b=2e-2),
xt.Drift(length=2.),
collimator,
xt.Multipole(knl=[0,0]),
xt.LimitEllipse(a=2e-2, b=2e-2),
xt.Drift(length=10.),
xt.LimitEllipse(a=2e-2, b=2e-2),
xt.Drift(length=10.),
])
#################
# Build tracker #
#################
line.build_tracker()
line.config.XTRACK_GLOBAL_XY_LIMIT = 1e3
##########################
# Build particles object #
##########################
# We prepare empty slots to store the product particles that will be
# generated during the tracking.
particles = xt.Particles(
_capacity=200000,
x=np.zeros(100000))
#########
# Track #
#########
line.track(particles)
############################
# Loss location refinement #
############################
loss_loc_refinement = xt.LossLocationRefinement(line,
n_theta = 360,
r_max = 0.5, # m
dr = 50e-6,
ds = 0.05,
save_refine_lines=True)
loss_loc_refinement.refine_loss_location(particles)
# Complete source: xtrack/examples/collimation/003_all_together.py