This example describes all of the major capabilities of particle beams in OSCARS. There are pre-defined particle types (default is electron, but proton, pion, etc are included) and the user is free to describe any other particle type they wish. Non-zero beam widths can be defined using the emittance, beta functions, and lattice reference (point at which the beta functions are defined). One can also define multiple particle beams in one OSCARS object and give weights to each.
Patricle beams can as well be defined, like other OSCARS objects, in any position and direction. Although examples are often given where $+\hat z$ is the beam direction (mostly to align with accelerator nomenclature), there is no preferred direction in OSCARS.
The minimum definition for a particle beam must include calling the two functions:
where tstart and tstop are the start and stop times for particle propoation. In the above set_particle_beam() will use all of its defaults (since no arguments are given) which is essentially an electron at rest at the origin. The defaults for set_particle_beam() are:
The elements which you may want to define for a beam are:
For a non-zero emittance beam you must additionally define the following (the beam shape is taken to be gaussian, though other distributions are possible):
For a particle beam you can additionally define the following:
Custom: If you set type='custom' you will need to also define the following:
The two functions for adding a particle beam are:
To see what beam(s) are setup in OSCARS you may call:
or to see everything we recommend:
# matplotlib plots inline
%matplotlib inline
# Import the OSCARS SR module
import oscars.sr
# Import OSCARS plots (matplotlib)
from oscars.plots_mpl import *
# Create an OSCARS SR object
osr = oscars.sr.sr()
# For these examples we will make use of a simple undulator field
osr.add_bfield_undulator(bfield=[0, 1, 0], period=[0, 0, 0.100], nperiods=5)
plot_bfield(osr)
These are basic beams with zero emittance, one electron (NSLSII energy) and one proton (LHC energy)
First example is showing full definition, second using the defaults for less typing.
# Add a basic electron beam with zero emittance
osr.set_particle_beam(type='electron', name='beam_0', energy_GeV=3, x0=[0, 0, -1], d0=[0, 0, 1], current=0.500)
# You MUST set the start and stop time for the calculation
osr.set_ctstartstop(0, 2)
# Plot trajectory of beam
plot_trajectory_position(osr.calculate_trajectory())
# Add a basic electron beam with zero emittance
osr.set_particle_beam(energy_GeV=3, x0=[0, 0, -1], current=0.500)
# You MUST set the start and stop time for the calculation
osr.set_ctstartstop(0, 2)
# Plot trajectory of beam
plot_trajectory_position(osr.calculate_trajectory())
This example shows how to define a proton beam at 13 TeV
# Add a basic proton beam with zero emittance
osr.set_particle_beam(type='proton', energy_GeV=13000, x0=[0, 0, -1], current=0.500)
# You MUST set the start and stop time for the calculation
osr.set_ctstartstop(0, 2)
# Plot trajectory of beam
plot_trajectory_position(osr.calculate_trajectory())
Beams can easily be rotated using the rotations variable. This essentialyl rotates the initial conditions given. It rotates the initial position x0 in space and rotates the direction vector d0.
# Add a basic proton beam and rotate it 45 degrees
osr.set_particle_beam(type='proton',
energy_GeV=13000,
x0=[0, 0, -1],
current=0.500,
rotations=[osr.pi()/4., 0, 0]
)
# You MUST set the start and stop time for the calculation
osr.set_ctstartstop(0, 2)
# Plot trajectory of beam
plot_trajectory_position(osr.calculate_trajectory())
This examples defined multiple beams in the same object, then plots the trajectory for two random particles selected from these beams.
Instead of using set_particle_beam we will use add_particle_beam (which is really the same thing, but set_particle_beam issues a clear_particle_beams() internally)
# Add basic electron beams with zero emittance
osr.clear_particle_beams()
osr.add_particle_beam(type='electron', name='beam_0', energy_GeV=3, x0=[0, 0, -1], current=0.500)
osr.add_particle_beam(type='positron', name='beam_1', energy_GeV=3, x0=[0, 0, -1], current=0.500)
osr.add_particle_beam(type='proton', name='beam_2', energy_GeV=13, x0=[0, 0, -1], current=0.500)
osr.add_particle_beam(type='muon', name='beam_3', energy_GeV=2, x0=[0, 0, -1], current=0.500)
osr.add_particle_beam(type='pi+', name='beam_4', energy_GeV=1, x0=[0, 0, -1], current=0.500)
# You MUST set the start and stop time for the calculation
osr.set_ctstartstop(0, 2)
# Plot trajectory of beam
plot_trajectory_position(osr.calculate_trajectory())
osr.set_new_particle()
plot_trajectory_position(osr.calculate_trajectory())
osr.set_new_particle()
plot_trajectory_position(osr.calculate_trajectory())
# Print particle beam info for checking
osr.print_particle_beams()
Below is an example of a beam with non-zero memittance. We use the emittance and the beta function. You must give the reference point for the beta function definition.
# Add a basic electron beam with zero emittance
osr.set_particle_beam(
energy_GeV=3,
x0=[0, 0, -1],
current=0.500,
sigma_energy_GeV=0.001*3,
beta=[1.5, 0.8],
emittance=[0.9e-9, 0.008e-9]
)
# You MUST set the start and stop time for the calculation
osr.set_ctstartstop(0, 2)
# Plot trajectory of beam
osr.set_new_particle()
plot_trajectory_position(osr.calculate_trajectory())
# Let's plot the distribution of particles at the initial position 'position'
energy = []
x = []
y = []
bx = []
by = []
for i in range(5000):
osr.set_new_particle()
energy.append(osr.get_particle_e0())
position = osr.get_particle_x0()
beta = osr.get_particle_beta0()
x.append(position[0])
y.append(position[1])
bx.append(beta[0])
by.append(beta[1])
plt.figure(1, figsize=[15, 3])
plt.subplot(131)
plt.scatter(x, y)
plt.xlim(-0.0005, 0.0005)
plt.ylim(-0.00005, 0.00005)
plt.xlabel('x0 [m]')
plt.ylabel('y0 [m]')
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
plt.ticklabel_format(style='sci', axis='y', scilimits=(0,0))
plt.subplot(132)
plt.scatter(bx, by)
plt.xlim(-0.0002, 0.0002)
plt.ylim(-0.00002, 0.00002)
plt.xlabel('x0 [m]')
plt.ylabel('y0 [m]')
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
plt.ticklabel_format(style='sci', axis='y', scilimits=(0,0))
plt.subplot(133)
plt.hist(energy)
plt.xlabel('Energy [GeV]')
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
plt.ticklabel_format(style='sci', axis='y', scilimits=(0,0))
plt.show()
A simple example of 2 beams with different beam parameters in the same object
# Add basic electron beams with zero emittance
osr.clear_particle_beams()
osr.add_particle_beam(
energy_GeV=3,
x0=[0, 0, -1],
current=0.500,
sigma_energy_GeV=0.001*3,
beta=[1.5, 0.8],
emittance=[0.9e-9, 0.008e-9],
weight=0.7
)
osr.add_particle_beam(
energy_GeV=3.02,
x0=[0, 0.000035, -1],
d0=[0, 0, 1],
current=0.500,
sigma_energy_GeV=0.001*3,
beta=[1.5, 0.8],
emittance=[0.9e-9, 0.008e-9],
weight=0.3
)
# You MUST set the start and stop time for the calculation
osr.set_ctstartstop(0, 2)
# And plot the results
energy = []
x = []
y = []
for i in range(5000):
osr.set_new_particle()
energy.append(osr.get_particle_e0())
position = osr.get_particle_x0()
x.append(position[0])
y.append(position[1])
plt.figure(1, figsize=[10, 3])
plt.subplot(121)
plt.scatter(x, y)
plt.xlim(-0.0005, 0.0005)
plt.ylim(-0.00005, 0.00005)
plt.xlabel('x0 [m]')
plt.ylabel('y0 [m]')
plt.subplot(122)
plt.hist(energy)
plt.xlabel('Energy [GeV]')
plt.show()
This is an example of a custom particle in OSCARS. All that additionally needs definition are the charge and mass
# Add a custom beam with zero emittance.
# This is for a particle with twice the chargs as the electron, but the same mass
osr.set_particle_beam(
type='custom',
charge=-2*osr.qe(),
mass=osr.me(),
energy_GeV=3,
x0=[0, 0, -1],
current=0.500
)
# You MUST set the start and stop time for the calculation
osr.set_ctstartstop(0, 2)
# Plot trajectory of beam
plot_trajectory_position(osr.calculate_trajectory())