Genesis4 Particles¶
This shows examples of the various ways to input particle data into Genesis4.
import logging
import os
from math import pi, sqrt
import matplotlib.pyplot as plt
import numpy as np
from scipy.constants import c
import genesis.version4 as g4
logging.basicConfig()
# logging.getLogger("genesis").setLevel("DEBUG")
%config InlineBackend.figure_format = 'retina'
Lattice¶
Create a simple drift lattice
D1 = g4.Drift(L=1)
lattice = g4.Lattice(elements={"D1": D1, "LAT": g4.Line(elements=[D1])})
profile_gauss
¶
This profile will make a Gaussian distribition. Here we do some calculations to make the correct bunch length for a given bunch charge to provide a peak current.
PEAK_CURRENT = 1000
BUNCH_CHARGE = 100e-12
SIGMA_T = BUNCH_CHARGE / (sqrt(2 * pi) * PEAK_CURRENT)
SIGMA_Z = SIGMA_T * c
SLEN = 6 * SIGMA_Z
S0 = 3 * SIGMA_Z
SIGMA_T, SIGMA_Z, SLEN
(3.989422804014327e-14, 1.1959988684167075e-05, 7.175993210500245e-05)
main = g4.MainInput(
namelists=[
g4.Setup(
rootname="drift_test",
# lattice="LATFILE",
beamline="LAT",
gamma0=1000,
lambda0=1e-07,
delz=0.026,
seed=123456,
npart=128,
),
g4.Time(slen=SLEN),
g4.ProfileGauss(
label="beamcurrent",
c0=PEAK_CURRENT,
s0=S0,
sig=SIGMA_Z,
),
g4.Beam(
gamma=1000,
delgam=1,
current="beamcurrent",
),
g4.Track(zstop=1),
g4.Write(beam="end"),
],
)
G = g4.Genesis4(main, lattice, verbose=True)
output = G.run()
Configured to run in: /tmp/tmpxxhjepl2 Running Genesis4 in /tmp/tmpxxhjepl2 /home/runner/miniconda3/envs/lume-genesis-dev/bin/genesis4 -l genesis.lat genesis4.in
--------------------------------------------- GENESIS - Version 4.6.7 has started... Compile info: Compiled by conda at 2024-12-09 17:34:26 [UTC] from Git Commit ID: f166211af8ded3543c5b983d3d6d8680af6ab767 Starting Time: Mon Jan 6 22:24:08 2025 MPI-Comm Size: 1 node Opened input file genesis4.in Parsing lattice file genesis.lat ... Setting up time window of 71.8 microns with 718 sample points... Adding profile with label: beamcurrent Generating input particle distribution... Running Core Simulation... Time-dependent run with 718 slices for a time window of 71.8 microns Initial analysis of electron beam and radiation field... Calculation: 0% done Writing output file... Core Simulation done. End of Track Writing particle distribution to file: end.par.h5 ...
Program is terminating... Ending Time: Mon Jan 6 22:24:09 2025 Total Wall Clock Time: 0.278625 seconds ------------------------------------- Success - execution took 1.46s.
G.input.main.setup.delz
0.026
print(G.output.run.output_log)
--------------------------------------------- GENESIS - Version 4.6.7 has started... Compile info: Compiled by conda at 2024-12-09 17:34:26 [UTC] from Git Commit ID: f166211af8ded3543c5b983d3d6d8680af6ab767 Starting Time: Mon Jan 6 22:24:08 2025 MPI-Comm Size: 1 node Opened input file genesis4.in Parsing lattice file genesis.lat ... Setting up time window of 71.8 microns with 718 sample points... Adding profile with label: beamcurrent Generating input particle distribution... Running Core Simulation... Time-dependent run with 718 slices for a time window of 71.8 microns Initial analysis of electron beam and radiation field... Calculation: 0% done Writing output file... Core Simulation done. End of Track Writing particle distribution to file: end.par.h5 ... Program is terminating... Ending Time: Mon Jan 6 22:24:09 2025 Total Wall Clock Time: 0.278625 seconds -------------------------------------
output.load_particles()
P1 = output.particles["end"]
P1.drift_to_z()
P1.plot("t", "energy")
P1
<ParticleGroup with 91904 particles at 0x7fc1025e74d0>
output.particles["end"]
<ParticleGroup with 91904 particles at 0x7fc1025e74d0>
Check the charge
P1.charge
np.float64(9.973150081144012e-11)
profile_file
¶
LUME-Genesis automatically makes an HDF5 file with ProfileArray
.
NPTS = 100
SLEN = 100e-6
S = np.linspace(0, SLEN, NPTS)
CURRENT = np.linspace(1, 1000.0, NPTS)
plt.plot(S, CURRENT)
[<matplotlib.lines.Line2D at 0x7fc101f5c190>]
main = g4.MainInput(
namelists=[
g4.Setup(
rootname="drift_test",
# lattice=lattice,
beamline="LAT",
gamma0=1000,
lambda0=1e-07,
delz=0.026,
seed=123456,
npart=128,
),
g4.Time(slen=SLEN),
g4.ProfileArray(label="beamcurrent", xdata=S, ydata=CURRENT),
g4.Beam(
gamma=1000,
delgam=1,
current="beamcurrent",
ex=1e-06,
ey=1e-06,
betax=7.910909406464387,
betay=16.881178621346898,
alphax=-0.7393217413918415,
alphay=1.3870723536888105,
),
g4.Track(zstop=1),
g4.Write(beam="end"),
]
)
G = g4.Genesis4(main, lattice, verbose=True)
output = G.run()
Configured to run in: /tmp/tmp1ufprho2 Running Genesis4 in /tmp/tmp1ufprho2 /home/runner/miniconda3/envs/lume-genesis-dev/bin/genesis4 -l genesis.lat genesis4.in
--------------------------------------------- GENESIS - Version 4.6.7 has started... Compile info: Compiled by conda at 2024-12-09 17:34:26 [UTC] from Git Commit ID: f166211af8ded3543c5b983d3d6d8680af6ab767 Starting Time: Mon Jan 6 22:24:12 2025 MPI-Comm Size: 1 node Opened input file genesis4.in Parsing lattice file genesis.lat ... Setting up time window of 100 microns with 1000 sample points... Adding profile with label: beamcurrent Generating input particle distribution... Running Core Simulation... Time-dependent run with 1000 slices for a time window of 100 microns Initial analysis of electron beam and radiation field... Calculation: 0% done Writing output file... Core Simulation done. End of Track Writing particle distribution to file: end.par.h5 ...
Program is terminating... Ending Time: Mon Jan 6 22:24:12 2025 Total Wall Clock Time: 0.370081 seconds ------------------------------------- Success - execution took 1.55s.
Inspect the input and output¶
print(main.to_genesis())
&setup rootname = drift_test lattice = genesis.lat beamline = LAT gamma0 = 1000.0 lambda0 = 1e-07 delz = 0.026 seed = 123456 npart = 128 &end &time slen = 0.0001 &end &profile_file label = beamcurrent xdata = ProfileArray_0.h5/x ydata = ProfileArray_0.h5/y &end &beam gamma = 1000.0 delgam = 1.0 current = @beamcurrent ex = 1e-06 ey = 1e-06 betax = 7.910909406464387 betay = 16.881178621346898 alphax = -0.7393217413918415 alphay = 1.3870723536888105 &end &track zstop = 1.0 &end &write beam = end &end
print(lattice.to_genesis())
D1: drift = {l=1.0}; LAT: LINE = {D1};
print(output.run.output_log)
--------------------------------------------- GENESIS - Version 4.6.7 has started... Compile info: Compiled by conda at 2024-12-09 17:34:26 [UTC] from Git Commit ID: f166211af8ded3543c5b983d3d6d8680af6ab767 Starting Time: Mon Jan 6 22:24:12 2025 MPI-Comm Size: 1 node Opened input file genesis4.in Parsing lattice file genesis.lat ... Setting up time window of 100 microns with 1000 sample points... Adding profile with label: beamcurrent Generating input particle distribution... Running Core Simulation... Time-dependent run with 1000 slices for a time window of 100 microns Initial analysis of electron beam and radiation field... Calculation: 0% done Writing output file... Core Simulation done. End of Track Writing particle distribution to file: end.par.h5 ... Program is terminating... Ending Time: Mon Jan 6 22:24:12 2025 Total Wall Clock Time: 0.370081 seconds -------------------------------------
output.meta
OutputMeta( extra={}, beamdumps=OutputMetaDumps(extra={}, filenames={}, intstep=array([], dtype=float64)), fielddumps=OutputMetaDumps(extra={}, filenames={}, intstep=array([], dtype=float64)), host='Undefined', input_file='&setup\n rootname = drift_test\n lattice = genesis.lat\n beamline = LAT\n gamma0 = 1000.0\n lambda0 = 1e-07\n delz = 0.026\n seed... lattice_file='D1: drift = {l=1.0};\nLAT: LINE = {D1};\n', time_stamp='Mon Jan 6 22:24:12 2025\n', user='runner', version=OutputMetaVersion( extra={}, build_info='Compiled by conda at 2024-12-09 17:34:26 [UTC] from Git Commit ID: f166211af8ded3543c5b983d3d6d8680af6ab767', major=4.0, minor=6.0, revision=7.0, ), cwd='/tmp/tmp1ufprho2', mpisize=1.0, )
output.load_particles()
P1 = output.particles["end"]
P1.drift_to_z()
P1.plot("t", "energy")
P1
<ParticleGroup with 128000 particles at 0x7fc101f9ad50>
Resample particles for equal weights. This is neccessary when reading from a distribution file.
NSAMPLE = len(P1)
P1r = P1.resample(NSAMPLE)
P1r.plot("t", "energy")
P1r
<ParticleGroup with 128000 particles at 0x7fc0f9549e50>
Make a more interesting distribution from this:
P1r.pz[0 : len(P1) // 2] *= 1.1
P1r.plot("t", "energy")
ParticleGroup can write to a file for Genesis4.
Please note that LUME-Genesis will write the distribution for you prior to running Genesis4, so this step is not necessary.
DIST_FILE = "genesis4_distribution.h5"
P1r.write_genesis4_distribution(DIST_FILE, verbose=True)
Resampling 128000 weighted particles
Datasets x, xp, y, yp, t, p written to: genesis4_distribution.h5
ParticleGroup¶
Genesis4Input directly supports OpenPMD-beamphysics ParticleGroup
instances.
When using the MainInput.initial_particles
property setter, LUME-Genesis will ensure the namelist is added before the first "Track" or "Write" namelist in the main input.
It will implicitly set the import_distribution
charge and the time.slen
to the calculated time window from the particles, equivalent to the following:
import_distribution.charge = particles.charge
main.time.slen = max(
c_light * np.ptp(particles.t),
np.ptp(particles.z),
)
Additionally, the appropriate input file for Genesis4 will be written automatically when Genesis4 is executed.
main = g4.MainInput(
namelists=[
g4.Setup(
rootname="drift_test",
# lattice=full_path(LATFILE),
beamline="LAT",
gamma0=1000,
lambda0=1e-07,
delz=0.026,
seed=123456,
npart=512,
),
g4.Time(slen=0), # This will change slen to span all particles
g4.Track(zstop=1),
g4.Write(beam="end"),
],
)
G1 = g4.Genesis4(main, lattice, verbose=True, initial_particles=P1r)
output = G1.run()
WARNING:genesis.version4.input.core:Updating time namelist slen: 0.000100 (was 0.000000) to span all particles
Configured to run in: /tmp/tmp81kywkfx Running Genesis4 in /tmp/tmp81kywkfx /home/runner/miniconda3/envs/lume-genesis-dev/bin/genesis4 -l genesis.lat genesis4.in
--------------------------------------------- GENESIS - Version 4.6.7 has started... Compile info: Compiled by conda at 2024-12-09 17:34:26 [UTC] from Git Commit ID: f166211af8ded3543c5b983d3d6d8680af6ab767 Starting Time: Mon Jan 6 22:25:22 2025 MPI-Comm Size: 1 node Opened input file genesis4.in Parsing lattice file genesis.lat ... Setting up time window of 100 microns with 1000 sample points... Importing distribution file... Charge of external distribution: 1.66782e-10 Particles in external distribution: 128000 Analysing external distribution... Analysis of the imported distribution Total Bunch Length (microns): 99.9505 Length for Matching (microns): 99.9505 Energy (MeV): 536.563 Norm. Emittance in x (micron): 1.00569 Norm. Emittance in y (micron): 1.00336 Beta Function in x (m): 9.96264 Beta Function in y (m): 14.8695 Alpha Function in x : -0.929478 Alpha Function in y : 1.2134 Beam center in x (micron): -0.0647826 Beam center in y (micron): -0.201185 Beam center in px : 1.13233e-08 Beam center in py : 5.10122e-10 Sorting external distribution... Global Sorting: Slicelength: 0 - Send backwards for theta < 4.99752e-07 - Send forward for theta > 9.94002e-05 *** Non-matching PArticle Transfar: Rank: 0 Deleted: 0 Forward: 1329 Backward: 5 Generating internal particle distribution...
Running Core Simulation... Time-dependent run with 1000 slices for a time window of 100 microns Initial analysis of electron beam and radiation field... Calculation: 0% done Writing output file... Core Simulation done. End of Track Writing particle distribution to file: end.par.h5 ...
Program is terminating... Ending Time: Mon Jan 6 22:25:23 2025 Total Wall Clock Time: 1.00652 seconds ------------------------------------- Success - execution took 30.80s.
output.run
RunInfo( error_reason='', run_script='/home/runner/miniconda3/envs/lume-genesis-dev/bin/genesis4 -l genesis.lat genesis4.in', run_time=30.80293348500004, )
output.load_particles()
P2 = output.particles["end"]
P2.z
array([9.96807718e-08, 2.15803028e-08, 5.58502820e-08, ..., 9.99474841e-05, 9.99723622e-05, 9.99975850e-05], shape=(512000,))
P2.drift_to_z()
P2.plot("t", "energy")
P2
<ParticleGroup with 512000 particles at 0x7fc101f70dd0>
P2.plot("weight", bins=100)
Notice that importdistribution
is filled in:
print(G1.input.to_genesis())
# Main input &setup rootname = drift_test lattice = genesis.lat beamline = LAT gamma0 = 1000.0 lambda0 = 1e-07 delz = 0.026 seed = 123456 npart = 512 &end &time slen = 9.999850899316347e-05 &end &importdistribution file = initial_particles.h5 charge = 1.667822143811236e-10 &end &track zstop = 1.0 &end &write beam = end &end # Lattice D1: drift = {l=1.0}; LAT: LINE = {D1};
Cleanup¶
G1.input.initial_particles
<ParticleGroup with 128000 particles at 0x7fc0f9549e50>
os.remove(DIST_FILE)