ZFEL SASE¶
Basic example of a SASE simulation.
In [1]:
Copied!
# (optional) installation
# !pip install git+https://github.com/slaclab/zfel.git@devel
# (optional) installation
# !pip install git+https://github.com/slaclab/zfel.git@devel
In [2]:
Copied!
from zfel import sase1d
import zfel.plot
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
%config InlineBackend.figure_format = 'retina'
from zfel import sase1d
import zfel.plot
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
%config InlineBackend.figure_format = 'retina'
Input¶
In [3]:
Copied!
sase_input = dict(
npart = 512, # n-macro-particles per bucket
s_steps = 200, # n-sample points along bunch length
z_steps = 200, # n-sample points along undulator
energy = 4313.34e6, # electron energy [eV]
eSpread = 0, # relative rms energy spread [1]
emitN = 1.2e-6, # normalized transverse emittance [m-rad]
currentMax = 3400, # peak current [Ampere]
beta = 26, # mean beta [meter]
unduPeriod = 0.03, # undulator period [meter]
unduK = 3.5 , # undulator parameter, K [1], array could taper.
unduL = 70, # length of undulator [meter]
radWavelength=None, # Will calculate based on resonance condition for unduK[0]
random_seed=31, # for reproducibility
particle_position=None, #np.genfromtxt('./Inputs/particle_position.csv', delimiter=',') # or None,
hist_rule='square-root', # 'square-root' or 'sturges' or 'rice-rule' or 'self-design', number \
# of intervals to generate the histogram of eta value in a bucket
iopt='sase',
P0 = 0 # small seed input power [W]
)
sase_input = dict(
npart = 512, # n-macro-particles per bucket
s_steps = 200, # n-sample points along bunch length
z_steps = 200, # n-sample points along undulator
energy = 4313.34e6, # electron energy [eV]
eSpread = 0, # relative rms energy spread [1]
emitN = 1.2e-6, # normalized transverse emittance [m-rad]
currentMax = 3400, # peak current [Ampere]
beta = 26, # mean beta [meter]
unduPeriod = 0.03, # undulator period [meter]
unduK = 3.5 , # undulator parameter, K [1], array could taper.
unduL = 70, # length of undulator [meter]
radWavelength=None, # Will calculate based on resonance condition for unduK[0]
random_seed=31, # for reproducibility
particle_position=None, #np.genfromtxt('./Inputs/particle_position.csv', delimiter=',') # or None,
hist_rule='square-root', # 'square-root' or 'sturges' or 'rice-rule' or 'self-design', number \
# of intervals to generate the histogram of eta value in a bucket
iopt='sase',
P0 = 0 # small seed input power [W]
)
Intermediate parameters¶
These are used internally
In [4]:
Copied!
params = sase1d.params_calc(**sase_input)
params.keys()
params = sase1d.params_calc(**sase_input)
params.keys()
Out[4]:
dict_keys(['unduJJ', 'gamma0', 'sigmaX2', 'kappa_1', 'density', 'Kai', 'ku', 'resWavelength', 'Pbeam', 'coopLength', 'z0', 'delt', 'dels', 'E02', 'gbar', 'delg', 'Ns', 'deta', 'rho'])
Run¶
In [5]:
Copied!
%%time
output = sase1d.sase(sase_input)
%%time
output = sase1d.sase(sase_input)
CPU times: user 7.52 s, sys: 1.31 ms, total: 7.52 s Wall time: 7.52 s
In [6]:
Copied!
output.keys()
output.keys()
Out[6]:
dict_keys(['Er', 'Ei', 'thet_final', 'eta_final', 'theta_final_slice_history', 'eta_final_slice_history', 'power_s', 'power_z', 'spectrum', 'params', 's', 'z', 'bunchLength', 'bunch_steps', 'freq'])
Plot output¶
In [7]:
Copied!
plt.ylabel('Power (GW)')
plt.xlabel('z (m)')
plt.plot(output['z'], output['power_z']/1e9)
plt.ylabel('Power (GW)')
plt.xlabel('z (m)')
plt.plot(output['z'], output['power_z']/1e9)
Out[7]:
[<matplotlib.lines.Line2D at 0x7ff28fe31280>]
In [8]:
Copied!
# Power evolution. z vs slice
plt.imshow( (output['Er']**2 + output['Ei']**2).T, origin='lower')
# Power evolution. z vs slice
plt.imshow( (output['Er']**2 + output['Ei']**2).T, origin='lower')
Out[8]:
<matplotlib.image.AxesImage at 0x7ff2870c1670>
In [9]:
Copied!
zfel.plot.plot_log_power_z(output)
zfel.plot.plot_log_power_z(output)
In [10]:
Copied!
zfel.plot.plot_power_s(output)
zfel.plot.plot_power_s(output)
In [11]:
Copied!
# plot spectrum
freq = output['freq']
spectrum = output['spectrum']
plt.plot(freq,spectrum[1:,-1])
plt.xlabel('energy (eV)')
plt.ylabel('spectrum (W/?)')
# plot spectrum
freq = output['freq']
spectrum = output['spectrum']
plt.plot(freq,spectrum[1:,-1])
plt.xlabel('energy (eV)')
plt.ylabel('spectrum (W/?)')
Out[11]:
Text(0, 0.5, 'spectrum (W/?)')
Particle history of final slice¶
In [12]:
Copied!
theta = output['theta_final_slice_history']
eta = output['eta_final_slice_history']
_, n_step = theta.shape
# particles, step along z
theta.shape
theta = output['theta_final_slice_history']
eta = output['eta_final_slice_history']
_, n_step = theta.shape
# particles, step along z
theta.shape
Out[12]:
(512, 201)
In [13]:
Copied!
# Function to plot a single step
def plot_step(i):
x = (theta[:,i] % 2*np.pi)/(2*np.pi) * 360
y = eta[:,i]*1e3
fig, ax = plt.subplots()
ax.set_title(f'Final slice, Step {i}')
ax.set_ylim(-6,6)
ax.set_xlabel(r'$\theta\, (deg)$')
ax.set_ylabel(r'$ \eta\, (10^{-3})$')
ax.scatter(x, y, marker='.', color='black')
plot_step(n_step-1)
# Function to plot a single step
def plot_step(i):
x = (theta[:,i] % 2*np.pi)/(2*np.pi) * 360
y = eta[:,i]*1e3
fig, ax = plt.subplots()
ax.set_title(f'Final slice, Step {i}')
ax.set_ylim(-6,6)
ax.set_xlabel(r'$\theta\, (deg)$')
ax.set_ylabel(r'$ \eta\, (10^{-3})$')
ax.scatter(x, y, marker='.', color='black')
plot_step(n_step-1)
In [14]:
Copied!
# interactive
#from ipywidgets import interact
#import ipywidgets as widgets
#interact(plot_step, i=widgets.IntSlider(min=0, max=n_step-1, step=1, value=n_step//2));
# interactive
#from ipywidgets import interact
#import ipywidgets as widgets
#interact(plot_step, i=widgets.IntSlider(min=0, max=n_step-1, step=1, value=n_step//2));