Write examples¶
# Useful for debugging
%load_ext autoreload
%autoreload 2
from pmd_beamphysics import ParticleGroup, pmd_init
from h5py import File
import os
# Pick one:
# H5File = 'data/bmad_particles2.h5'
H5FILE = "data/distgen_particles.h5"
# H5FILE = 'data/astra_particles.h5'
P = ParticleGroup(H5FILE)
openPMD¶
The regular write routine writes in a proper openPMD format
P.write("openpmd_particles.h5")
An open h5 hande can also be used, but it needs to be properly initialized
with File("openpmd_particles.h5", "w") as h5:
pmd_init(h5, basePath="/", particlesPath="/")
P.write(h5)
This can be read in by another ParticleGroup
P2 = ParticleGroup("openpmd_particles.h5")
Check that they are the same:
P2 == P
True
Astra¶
P.write_astra("astra_particles.txt")
!head astra_particles.txt
-1.289814080985e-05 1.712192978919e-05 0.000000000000e+00 -9.245284702413e-01 -3.316650265292e+00 2.210558337183e+02 1.819664001274e-05 0.000000000000e+00 1 5 -1.184861337727e-03 -2.101371437059e-03 0.000000000000e+00 -3.047044656318e+02 -3.039342419008e+02 -1.005645891013e+02 -9.745607002167e-04 1.000000000000e-06 1 5 -5.181307340245e-04 -2.178353405029e-03 0.000000000000e+00 5.525456229648e+02 2.416723877028e+02 -6.554342847563e+01 1.280843753434e-03 1.000000000000e-06 1 5 -1.773501610902e-03 2.864979597813e-03 0.000000000000e+00 -2.226004747820e+02 9.450238076106e+00 -1.055085411491e+02 3.835366744569e-04 1.000000000000e-06 1 5 1.686555815999e-03 -2.401048305081e-04 0.000000000000e+00 -1.891692499417e+02 4.859547751754e+01 3.339263495319e+02 1.902998338336e-03 1.000000000000e-06 1 5 -7.779454935491e-04 -6.800063114796e-04 0.000000000000e+00 6.716138938638e+01 -2.064173000222e+02 -1.405963302134e+02 1.779005092730e-04 1.000000000000e-06 1 5 -2.593702199590e-03 -2.301030494125e-03 0.000000000000e+00 -1.455653402031e+01 2.074634953296e+02 -1.397453142110e+02 1.368567098305e-03 1.000000000000e-06 1 5 1.997801509161e-03 2.648416193086e-03 0.000000000000e+00 -2.124047726665e+00 -6.792723569247e+01 6.931081537770e+01 2.616497721112e-04 1.000000000000e-06 1 5 1.999741847023e-03 -6.945690451493e-04 0.000000000000e+00 -9.991142908925e+01 -9.189412445573e+01 2.259539675809e+02 -8.681109991004e-04 1.000000000000e-06 1 5 -7.033822974359e-04 -5.677746866954e-04 0.000000000000e+00 7.520962264129e+02 3.125940718167e+02 -1.451032665210e+02 4.315191990002e-04 1.000000000000e-06 1 5
Check the readback:
from pmd_beamphysics.interfaces.astra import parse_astra_phase_file
import numpy as np
P1 = ParticleGroup(data=parse_astra_phase_file("astra_particles.txt"))
for k in ["x", "px", "y", "py", "z", "pz"]:
assert np.allclose(P[k], P1[k])
Bmad ASCII¶
P.write_bmad("bmad_particles.txt")
!head bmad_particles.txt
!ASCII::3 0 ! ix_ele, not used 1 ! n_bunch 10000 ! n_particle BEGIN_BUNCH electron 1.0000000000000003e-11 ! bunch_charge 0 ! z_center 0 ! t_center -1.184861337727e-03 -3.047044656318e+02 -2.101371437059e-03 -3.039342419008e+02 -9.563640602039e-13 1.204912446170e+02 1.000000000000e-15 1
Bmad dict¶
P.to_bmad()
{'x': array([-0.00118486, -0.00051813, -0.0017735 , ..., -0.00052658, 0.00252813, 0.00113815]), 'y': array([-0.00210137, -0.00217835, 0.00286498, ..., -0.00161154, 0.00160049, -0.0010351 ]), 'px': array([-0.69011879, 1.25144906, -0.50416317, ..., 0.60249121, 0.505233 , 0.74928061]), 'py': array([-0.68837433, 0.54735875, 0.02140365, ..., -0.07882388, 0.29433475, -0.25918357]), 'z': array([ 2.55529374e-07, -4.68009162e-07, -5.64739756e-08, ..., -9.69805227e-09, 4.20165276e-07, 2.70278113e-07]), 'pz': array([ 0.01222356, 0.41059669, -0.4315584 , ..., -0.3093279 , 0.02463904, 0.08781142]), 'charge': array([1.e-15, 1.e-15, 1.e-15, ..., 1.e-15, 1.e-15, 1.e-15]), 'species': 'electron', 'p0c': np.float64(441.52466167250947), 'tref': np.float64(1.8196640012738955e-14), 'state': array([1, 1, 1, ..., 1, 1, 1])}
Check that the conversion preserves information. Note that ==
uses np.allclose
, because there is roundoff error in the conversion.
assert P == P.from_bmad(P.to_bmad())
elegant¶
P.write_elegant("elegant_particles.txt", verbose=True)
writing 10000 particles to elegant_particles.txt
!head -n 20 elegant_particles.txt
SDDS1 ! ! Created using the openPMD-beamphysics Python package ! https://github.com/ChristopherMayes/openPMD-beamphysics ! species: electron ! ¶meter name=Charge, type=double, units=C, description="total charge in Coulombs" &end &column name=t, type=double, units=s, description="time in seconds" &end &column name=x, type=double, units=m, description="x in meters" &end &column name=xp, type=double, description="px/pz" &end &column name=y, type=double, units=m, description="y in meters" &end &column name=yp, type=double, description="py/pz" &end &column name=p, type=double, units="m$be$nc", description="relativistic gamma*beta" &end &data mode=ascii &end 1.0000000000000003e-11 10000 -9.563640602039e-13 -1.184861337727e-03 -2.528851507845e+00 -2.101371437059e-03 -2.522459145201e+00 8.746038816275e-04 1.299040393447e-12 -5.181307340245e-04 3.553064606663e+00 -2.178353405029e-03 1.554039289185e+00 1.218815083118e-03 4.017333144697e-13 -1.773501610902e-03 -1.926488019169e+00 2.864979597813e-03 8.178675472159e-02 4.911575370556e-04 1.921194978349e-12 1.686555815999e-03 -3.408564376497e-01 -2.401048305081e-04 8.756222989528e-02 1.151365621035e-03
Genesis 1.3 v2¶
P.write_genesis2_beam_file("genesis2.beam", n_slice=50, verbose=True)
Beam written: genesis2.beam
!head genesis2.beam
? VERSION=1.0 ? SIZE=50 ? COLUMNS TPOS CURPEAK GAMMA0 DELGAM EMITX EMITY RXBEAM RYBEAM XBEAM YBEAM PXBEAM PYBEAM ALPHAX ALPHAY -1.96236040e-12 2.75359318e+00 1.00000042e+00 3.87022121e-07 1.19639887e-06 9.26536586e-07 2.04948080e-03 1.83621527e-03 -2.06231144e-04 5.85738124e-05 1.38209180e-05 4.17553934e-05 -1.01973407e-02 7.54079832e-04 -1.88646733e-12 2.46723994e+00 1.00000043e+00 3.39783124e-07 1.04698472e-06 1.03470799e-06 2.05064183e-03 1.92139881e-03 -2.53107201e-05 -1.13678787e-04 -2.85190907e-05 -2.90105675e-05 -2.32400675e-02 -2.55583997e-03 -1.80734757e-12 2.61898031e+00 1.00000043e+00 3.65257967e-07 9.78086023e-07 1.03038032e-06 1.97065976e-03 1.88550433e-03 -7.56576638e-05 1.77044304e-04 -4.48907172e-05 6.98821769e-05 5.38708456e-03 4.70844009e-03 -1.72583745e-12 2.30361285e+00 1.00000043e+00 3.43343193e-07 9.42099457e-07 1.07137205e-06 1.90156644e-03 1.92054974e-03 4.82559113e-05 -6.43105052e-05 1.66595205e-05 1.33986604e-05 9.16890850e-02 8.20635086e-03 -1.64047654e-12 2.48779835e+00 1.00000043e+00 3.76740497e-07 1.12901501e-06 1.01496464e-06 2.07085748e-03 1.84284581e-03 -2.63780641e-04 2.16425678e-05 9.07228824e-06 -2.65046022e-05 1.91567484e-03 3.63234933e-03 -1.55820367e-12 2.33273410e+00 1.00000041e+00 3.38657590e-07 9.79796547e-07 1.04648255e-06 1.84685458e-03 1.99189484e-03 3.36520774e-05 1.02123362e-04 3.01402301e-06 6.13937003e-05 -7.84493116e-02 2.84788841e-02 -1.47800120e-12 2.62363489e+00 1.00000044e+00 3.34570582e-07 1.12580877e-06 1.08628803e-06 1.97095399e-03 2.02149469e-03 -1.94415715e-04 -1.05666747e-04 -1.70675102e-05 -5.61809635e-06 -1.81522208e-01 -5.08353286e-03
Genesis 1.3 v4¶
beam file (slice statistics)¶
input_str = P.write_genesis4_beam(
"genesis4_beam.h5", n_slice=123, verbose=True, return_input_str=True
)
Genesis4 beam file written: genesis4_beam.h5
This string is optionally returned for use in the main Genesis4 input file:
print(input_str)
&profile_file label = current xdata = genesis4_beam.h5/t ydata = genesis4_beam.h5/current isTime = T reverse = T &end &profile_file label = gamma xdata = genesis4_beam.h5/t ydata = genesis4_beam.h5/gamma isTime = T reverse = T &end &profile_file label = delgam xdata = genesis4_beam.h5/t ydata = genesis4_beam.h5/delgam isTime = T reverse = T &end &profile_file label = ex xdata = genesis4_beam.h5/t ydata = genesis4_beam.h5/ex isTime = T reverse = T &end &profile_file label = ey xdata = genesis4_beam.h5/t ydata = genesis4_beam.h5/ey isTime = T reverse = T &end &profile_file label = xcenter xdata = genesis4_beam.h5/t ydata = genesis4_beam.h5/xcenter isTime = T reverse = T &end &profile_file label = ycenter xdata = genesis4_beam.h5/t ydata = genesis4_beam.h5/ycenter isTime = T reverse = T &end &profile_file label = pxcenter xdata = genesis4_beam.h5/t ydata = genesis4_beam.h5/pxcenter isTime = T reverse = T &end &profile_file label = pycenter xdata = genesis4_beam.h5/t ydata = genesis4_beam.h5/pycenter isTime = T reverse = T &end &profile_file label = alphax xdata = genesis4_beam.h5/t ydata = genesis4_beam.h5/alphax isTime = T reverse = T &end &profile_file label = alphay xdata = genesis4_beam.h5/t ydata = genesis4_beam.h5/alphay isTime = T reverse = T &end &profile_file label = betax xdata = genesis4_beam.h5/t ydata = genesis4_beam.h5/betax isTime = T reverse = T &end &profile_file label = betay xdata = genesis4_beam.h5/t ydata = genesis4_beam.h5/betay isTime = T reverse = T &end &beam current = @current gamma = @gamma delgam = @delgam ex = @ex ey = @ey xcenter = @xcenter ycenter = @ycenter pxcenter = @pxcenter pycenter = @pycenter alphax = @alphax alphay = @alphay betax = @betax betay = @betay &end
These are the datasets written:
with File("genesis4_beam.h5", "r") as h5:
for g in h5:
print(g, len(h5[g]), h5[g].attrs["unitSymbol"])
alphax 123 alphay 123 betax 123 m betay 123 m current 123 A delgam 123 ex 123 m ey 123 m gamma 123 pxcenter 123 pycenter 123 t 123 s xcenter 123 m ycenter 123 m
Distribution file (particles)¶
P.write_genesis4_distribution("genesis4_distribution.h5", verbose=True)
Datasets x, xp, y, yp, t, p written to: genesis4_distribution.h5
This is what is written:
with File("genesis4_distribution.h5", "r") as h5:
for g in h5:
print(g, len(h5[g]))
p 10000 t 10000 x 10000 xp 10000 y 10000 yp 10000
GPT ASCII¶
P.write_gpt("gpt_particles.txt", verbose=True)
writing 10000 particles to gpt_particles.txt ASCII particles written. Convert to GDF using: asci2df -o particles.gdf gpt_particles.txt
if os.path.exists(os.path.expandvars("$ASCI2GDF_BIN")):
P.write_gpt("gpt_particles.gdf", verbose=True, asci2gdf_bin="$ASCI2GDF_BIN")
#!head gpt_particles.txt
Impact-T¶
Impact-T particles must all be a the same time:
P.drift_to_t(P["mean_t"])
This will return settings for Impact-T to use:
P.write_impact("impact_particles.txt")
{'input_particle_file': 'impact_particles.txt', 'Np': 10000, 'Tini': np.float64(1.8196640012738955e-14), 'Flagimg': 0}
!head impact_particles.txt
10000 -1.185035553808772143e-03 -5.962917646539026830e-04 -2.101545212762252063e-03 -5.947844744118675406e-04 6.889138464881934423e-08 2.357954837617718942e-04 -5.185459410277813361e-04 1.081304810831444467e-03 -2.178535008255722601e-03 4.729410651485857963e-04 -1.168588385748075652e-07 3.043301854978374224e-04 -1.773451522909312962e-03 -4.356182625855454594e-04 2.864977471386669170e-03 1.849365458795189412e-05 -2.599963881922582336e-08 2.261204109504710640e-04 1.686767013783966630e-03 -3.701949875665073173e-04 -2.401590848712557098e-04 9.509897724357652376e-05 -6.196091998406064887e-07 1.086073040365844247e-03 -7.779525032181127363e-04 1.314315604491483489e-04 -6.799847675988795461e-04 -4.039485795854574836e-04 -8.397600117458311948e-09 1.574553206124528761e-04 -2.593690512006350136e-03 -2.848642647956871966e-05 -2.301197068594195913e-03 4.059959327304890142e-04 -6.528501143099030074e-08 1.591207173856017771e-04 1.997801835211931738e-03 -4.156657712632428962e-06 2.648426620219643604e-03 -1.329302842842789139e-04 -4.457257401140207729e-08 5.682333576145901953e-04 1.999690961886589624e-03 -1.955217894072916647e-04 -6.946158470527933476e-04 -1.798323156157682705e-04 2.276631907326255499e-07 8.747763597149907193e-04 -7.035727003852429310e-04 1.471815600429043306e-03 -5.678538239535645561e-04 6.117313388152665482e-04 -1.922838101944327160e-08 1.486354662711140203e-04
LiTrack¶
LiTrack particles must be at the same z:
P.drift_to_z()
P.write_litrack("litrack.zd", verbose=True)
Using mean_p as the reference momentum: 441.52466167250947 eV/c writing 10000 LiTrack particles to litrack.zd
'litrack.zd'
!head -n 20 litrack.zd
% LiTrack particles % % Created using the openPMD-beamphysics Python package % https://github.com/ChristopherMayes/openPMD-beamphysics % % species: electron % n_particle: 10000 % total charge: 1.0000000000000003e-11 (C) % reference momentum p0: 441.52466167250947 (eV/c) % % Columns: ct, delta = p/p0 -1 % Units: mm, percent -2.910140500388e-01 1.222356070583e+00 3.861082943987e-01 4.105966931910e+01 1.159491741202e-01 -4.315583986424e+01 5.750254785583e-01 3.325339997689e+01 5.234406211768e-02 -4.756793241308e+01 4.093643740668e-01 -4.942448528425e+01 8.211012905157e-02 -3.245820052454e+01 -2.559578717432e-01 5.807578013130e+00
Lucretia¶
P.write_lucretia(
"lucretia.mat", ele_name="BEGINNING", t_ref=0, stop_ix=None, verbose=True
)
writing 10000 particles in the Lucretia format to lucretia.mat
Read back:
from pmd_beamphysics.interfaces.lucretia import lucretia_to_data, list_element_names
ParticleGroup(data=lucretia_to_data("lucretia.mat", verbose=True))
1 elements found in the file! 10000 particles detected, 0 found dead!
<ParticleGroup with 10000 particles at 0x7f542f69ef20>
Helper function to list the available elements:
list_element_names("lucretia.mat")
['BEGINNING']
OPAL¶
Injected particled must be at the same time:
P.drift_to_t()
P.write_opal("opal_injected.txt", dist_type="injected")
!head opal_injected.txt
10000 -1.185024568260e-03 -5.962917646539e-04 -2.101534254983e-03 -5.947844744119e-04 6.454729863911e-08 2.357954837618e-04 -5.185658620175e-04 1.081304810831e-03 -2.178543721298e-03 4.729410651486e-04 -1.224655448770e-07 3.043301854978e-04 -1.773443497464e-03 -4.356182625855e-04 2.864977130676e-03 1.849365458795e-05 -3.016548099423e-08 2.261204109505e-04 1.686773833925e-03 -3.701949875665e-04 -2.401608368896e-04 9.509897724358e-05 -6.396180367454e-07 1.086073040366e-03 -7.779549245968e-04 1.314315604491e-04 -6.799773256079e-04 -4.039485795855e-04 -1.129841753741e-08 1.574553206125e-04 -2.593689987198e-03 -2.848642647957e-05 -2.301204548304e-03 4.059959327305e-04 -6.821651066751e-08 1.591207173856e-04 1.997801911791e-03 -4.156657712632e-06 2.648429069209e-03 -1.329302842843e-04 -5.504120158406e-08 5.682333576146e-04 1.999694564006e-03 -1.955217894073e-04 -6.946125339825e-04 -1.798323156158e-04 2.115470906675e-07 8.747763597150e-04 -7.035998157808e-04 1.471815600429e-03 -5.678650939369e-04 6.117313388153e-04 -2.196670602435e-08 1.486354662711e-04
Emitted particles must be at the same z:
P.drift_to_z(P["mean_z"])
P.write_opal("opal_emitted.txt", dist_type="emitted")
!head opal_emitted.txt
10000 -1.184838617375e-03 -5.962917646539e-04 -2.101348774139e-03 -5.947844744119e-04 -1.083461177889e-12 2.357954837618e-04 -5.181626563723e-04 1.081304810831e-03 -2.178367367225e-03 4.729410651486e-04 1.200565320731e-12 3.043301854978e-04 -1.773484302458e-03 -4.356182625855e-04 2.864978863003e-03 1.849365458795e-05 2.691980940714e-13 2.261204109505e-04 1.686558878409e-03 -3.701949875665e-04 -2.401056172069e-04 9.509897724358e-05 1.893601130019e-12 1.086073040366e-03 -7.779529930790e-04 1.314315604491e-04 -6.799832620349e-04 -4.039485795855e-04 5.764311716727e-15 1.574553206125e-04 -2.593700591157e-03 -2.848642647957e-05 -2.301053417928e-03 4.059959327305e-04 1.198422972634e-12 1.591207173856e-04 1.997801574883e-03 -4.156657712632e-06 2.648418294875e-03 -1.329302842843e-04 2.271058970013e-13 5.682333576146e-04 1.999743855144e-03 -1.955217894073e-04 -6.945671981683e-04 -1.798323156158e-04 -8.841733180528e-13 8.747763597150e-04 -7.034712631509e-04 1.471815600429e-03 -5.678116635531e-04 6.117313388153e-04 2.480886363183e-13 1.486354662711e-04
SIMION¶
Write SIMION input files (*.ion)
P.write_simion("simion_particles.ion")
Cleanup¶
for file in [
"astra_particles.txt",
"bmad_particles.txt",
"elegant_particles.txt",
"gpt_particles.txt",
"impact_particles.txt",
"opal_injected.txt",
"opal_emitted.txt",
"openpmd_particles.h5",
"genesis4_beam.h5",
"genesis4_distribution.h5",
"genesis2.beam",
"litrack.zd",
"gpt_particles.gdf",
"lucretia.mat",
"simion_particles.ion",
]:
if os.path.exists(file):
os.remove(file)