Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
03dc3c3
start of PolygonAperture implementation
egstern Oct 22, 2025
229ab2a
PolygonAperture logic added and builds now.
egstern Oct 24, 2025
680b89c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 24, 2025
a86705d
Update src/elements/PolygonAperture.H
egstern Oct 27, 2025
26da419
Added input file parsing logic.
egstern Nov 3, 2025
42120dc
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 3, 2025
f65dd08
Update src/elements/PolygonAperture.H
cemitch99 Nov 4, 2025
23e0f40
sense of test was incorrect
egstern Nov 4, 2025
55e8bdf
input file example
egstern Nov 4, 2025
6b9a5b8
some problem merging upstream? I don't know what happened
egstern Nov 4, 2025
8461e9d
examples of aperture with offsets and rotations
egstern Nov 4, 2025
e93a870
Rearrange storage of vertices data and min_radius2 so that
egstern Nov 5, 2025
d07b51a
script to plot the action of the aperture
egstern Nov 6, 2025
7aa179b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 6, 2025
af944bb
tweaks to plot layout
egstern Nov 6, 2025
3d414ef
tweaks to plot layout
egstern Nov 6, 2025
bac3829
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 6, 2025
ef0c3ce
New analysis script that checks tests the results of the aperture, small
egstern Nov 7, 2025
95fe1ee
I don't know why this changed upstream
egstern Nov 7, 2025
b3df98f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 7, 2025
d91ed97
python bindings for polygon aperture
egstern Nov 11, 2025
7fde375
python example file for the polygon aperture
egstern Nov 11, 2025
9cd397a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Nov 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions examples/polygon_aperture/analysis_polygon_aperture.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/env python3
#
# Copyright 2022-2023 ImpactX contributors
# Authors: Eric G. Stern, Axel Huebl, Chad Mitchell
# License: BSD-3-Clause-LBNL
#


import numpy as np
import openpmd_api as io

# initial/final beam
series = io.Series("diags/openPMD/monitor.h5", io.Access.read_only)
last_step = list(series.iterations)[-1]
initial = series.iterations[1].particles["beam"].to_df()
beam_final = series.iterations[last_step].particles["beam"]
final = beam_final.to_df()

# compare number of particles
num_particles = len(initial.momentum_x)
assert num_particles == len(initial)
assert num_particles != len(final)

print("Initial Beam: ", len(initial), " particles")
print("Final Beam: ", len(final), " particles")

# Make sure no particles are outside of the aperture in the final particle set
abs_x_final = abs(final["position_x"]).to_numpy()
abs_y_final = abs(final["position_y"]).to_numpy()

N = abs_x_final.shape[0]
insides = np.zeros(N, dtype=np.bool)
for i in range(N):
insides[i] = ((abs_y_final[i] < 0.5e-3) and (abs_x_final[i] < 1.5e-3)) or (
(abs_x_final[i] < 0.5e-3) and (abs_y_final[i] < 1.5e-3)
)


outsides = ~insides
ninside = insides.sum()
noutside = outsides.sum()

assert ninside == len(final)
assert noutside == 0
46 changes: 46 additions & 0 deletions examples/polygon_aperture/input_polygon_aperture.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
###############################################################################
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wonderful!

Please add your tests to examples/CMakeLists.txt

# Particle Beam(s)
###############################################################################
beam.npart = 50000
beam.units = static
beam.kin_energy = 800.0
beam.charge = 1.0e-9
beam.particle = proton
beam.distribution = waterbag
beam.lambdaX = 2.0e-3
beam.lambdaY = beam.lambdaX
beam.lambdaT = 0.4
beam.lambdaPx = 4.0e-4
beam.lambdaPy = beam.lambdaPx
beam.lambdaPt = 2.0e-3
beam.muxpx = 0.0
beam.muypy = 0.0
beam.mutpt = 0.0


###############################################################################
# Beamline: lattice elements and segments
###############################################################################
lattice.elements = monitor pa monitor
lattice.nslice = 1

monitor.type = beam_monitor
monitor.backend = h5

pa.type = polygon_aperture
pa.vertices_x = 0.5e-3 0.5e-3 -0.5e-3 -0.5e-3 -1.5e-3 -1.5e-3 -0.5e-3 -0.5e-3 0.5e-3 0.5e-3 1.5e-3 1.5e-3 0.5e-3
pa.vertices_y = 0.5e-3 1.5e-3 1.5e-3 0.5e-3 0.5e-3 -0.5e-3 -0.5e-3 -1.5e-3 -1.5e-3 -0.5e-3 -0.5e-3 0.5e-3 0.5e-3
pa.min_radius2 = 5.0e-7
pa.action = "transmit" # this is the default transmit particles within the polygon
#pa.action = "absorb" # alternatively absorb particles within the polygon

###############################################################################
# Algorithms
###############################################################################
algo.space_charge = false


###############################################################################
# Diagnostics
###############################################################################
diag.slice_step_diagnostics = true
45 changes: 45 additions & 0 deletions examples/polygon_aperture/input_polygon_aperture_absorb.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
###############################################################################
# Particle Beam(s)
###############################################################################
beam.npart = 50000
beam.units = static
beam.kin_energy = 800.0
beam.charge = 1.0e-9
beam.particle = proton
beam.distribution = waterbag
beam.lambdaX = 2.0e-3
beam.lambdaY = beam.lambdaX
beam.lambdaT = 0.4
beam.lambdaPx = 4.0e-4
beam.lambdaPy = beam.lambdaPx
beam.lambdaPt = 2.0e-3
beam.muxpx = 0.0
beam.muypy = 0.0
beam.mutpt = 0.0


###############################################################################
# Beamline: lattice elements and segments
###############################################################################
lattice.elements = monitor pa monitor
lattice.nslice = 1

monitor.type = beam_monitor
monitor.backend = h5

pa.type = polygon_aperture
pa.vertices_x = 0.5e-3 0.5e-3 -0.5e-3 -0.5e-3 -1.5e-3 -1.5e-3 -0.5e-3 -0.5e-3 0.5e-3 0.5e-3 1.5e-3 1.5e-3 0.5e-3
pa.vertices_y = 0.5e-3 1.5e-3 1.5e-3 0.5e-3 0.5e-3 -0.5e-3 -0.5e-3 -1.5e-3 -1.5e-3 -0.5e-3 -0.5e-3 0.5e-3 0.5e-3
pa.min_radius2 = 5.0e-7
pa.action = "absorb" # absorb particles within the polygon

###############################################################################
# Algorithms
###############################################################################
algo.space_charge = false


###############################################################################
# Diagnostics
###############################################################################
diag.slice_step_diagnostics = true
47 changes: 47 additions & 0 deletions examples/polygon_aperture/input_polygon_aperture_absorb_offset.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
###############################################################################
# Particle Beam(s)
###############################################################################
beam.npart = 50000
beam.units = static
beam.kin_energy = 800.0
beam.charge = 1.0e-9
beam.particle = proton
beam.distribution = waterbag
beam.lambdaX = 2.0e-3
beam.lambdaY = beam.lambdaX
beam.lambdaT = 0.4
beam.lambdaPx = 4.0e-4
beam.lambdaPy = beam.lambdaPx
beam.lambdaPt = 2.0e-3
beam.muxpx = 0.0
beam.muypy = 0.0
beam.mutpt = 0.0


###############################################################################
# Beamline: lattice elements and segments
###############################################################################
lattice.elements = monitor pa monitor
lattice.nslice = 1

monitor.type = beam_monitor
monitor.backend = h5

pa.type = polygon_aperture
pa.vertices_x = 0.5e-3 0.5e-3 -0.5e-3 -0.5e-3 -1.5e-3 -1.5e-3 -0.5e-3 -0.5e-3 0.5e-3 0.5e-3 1.5e-3 1.5e-3 0.5e-3
pa.vertices_y = 0.5e-3 1.5e-3 1.5e-3 0.5e-3 0.5e-3 -0.5e-3 -0.5e-3 -1.5e-3 -1.5e-3 -0.5e-3 -0.5e-3 0.5e-3 0.5e-3
pa.min_radius2 = 5.0e-7
pa.action = "absorb" # absorb particles within the polygon
pa.dx = 0.0006
pa.dy = -0.0012

###############################################################################
# Algorithms
###############################################################################
algo.space_charge = false


###############################################################################
# Diagnostics
###############################################################################
diag.slice_step_diagnostics = true
46 changes: 46 additions & 0 deletions examples/polygon_aperture/input_polygon_aperture_absorb_rotate.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
###############################################################################
# Particle Beam(s)
###############################################################################
beam.npart = 50000
beam.units = static
beam.kin_energy = 800.0
beam.charge = 1.0e-9
beam.particle = proton
beam.distribution = waterbag
beam.lambdaX = 2.0e-3
beam.lambdaY = beam.lambdaX
beam.lambdaT = 0.4
beam.lambdaPx = 4.0e-4
beam.lambdaPy = beam.lambdaPx
beam.lambdaPt = 2.0e-3
beam.muxpx = 0.0
beam.muypy = 0.0
beam.mutpt = 0.0


###############################################################################
# Beamline: lattice elements and segments
###############################################################################
lattice.elements = monitor pa monitor
lattice.nslice = 1

monitor.type = beam_monitor
monitor.backend = h5

pa.type = polygon_aperture
pa.vertices_x = 0.5e-3 0.5e-3 -0.5e-3 -0.5e-3 -1.5e-3 -1.5e-3 -0.5e-3 -0.5e-3 0.5e-3 0.5e-3 1.5e-3 1.5e-3 0.5e-3
pa.vertices_y = 0.5e-3 1.5e-3 1.5e-3 0.5e-3 0.5e-3 -0.5e-3 -0.5e-3 -1.5e-3 -1.5e-3 -0.5e-3 -0.5e-3 0.5e-3 0.5e-3
pa.min_radius2 = 5.0e-7
pa.action = "absorb" # absorb particles within the polygon
pa.rotation = 30.0 # degrees?

###############################################################################
# Algorithms
###############################################################################
algo.space_charge = false


###############################################################################
# Diagnostics
###############################################################################
diag.slice_step_diagnostics = true
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
###############################################################################
# Particle Beam(s)
###############################################################################
beam.npart = 50000
beam.units = static
beam.kin_energy = 800.0
beam.charge = 1.0e-9
beam.particle = proton
beam.distribution = waterbag
beam.lambdaX = 2.0e-3
beam.lambdaY = beam.lambdaX
beam.lambdaT = 0.4
beam.lambdaPx = 4.0e-4
beam.lambdaPy = beam.lambdaPx
beam.lambdaPt = 2.0e-3
beam.muxpx = 0.0
beam.muypy = 0.0
beam.mutpt = 0.0


###############################################################################
# Beamline: lattice elements and segments
###############################################################################
lattice.elements = monitor pa monitor
lattice.nslice = 1

monitor.type = beam_monitor
monitor.backend = h5

pa.type = polygon_aperture
pa.vertices_x = 0.5e-3 0.5e-3 -0.5e-3 -0.5e-3 -1.5e-3 -1.5e-3 -0.5e-3 -0.5e-3 0.5e-3 0.5e-3 1.5e-3 1.5e-3 0.5e-3
pa.vertices_y = 0.5e-3 1.5e-3 1.5e-3 0.5e-3 0.5e-3 -0.5e-3 -0.5e-3 -1.5e-3 -1.5e-3 -0.5e-3 -0.5e-3 0.5e-3 0.5e-3
pa.min_radius2 = 5.0e-7
pa.action = "absorb" # absorb particles within the polygon
pa.rotation = 30.0 # degrees?
pa.dx = 0.0006
pa.dy = -0.0012
###############################################################################
# Algorithms
###############################################################################
algo.space_charge = false


###############################################################################
# Diagnostics
###############################################################################
diag.slice_step_diagnostics = true
49 changes: 49 additions & 0 deletions examples/polygon_aperture/plot_polygon_aperture.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/usr/bin/env python3
#
# Copyright 2022-2025 ImpactX contributors
# Authors: Eric G. Stern, Axel Huebl, Chad Mitchell
# License: BSD-3-Clause-LBNL
#

import argparse

import matplotlib.pyplot as plt
import openpmd_api as io

# options to run this script
parser = argparse.ArgumentParser(description="Plot action of the polygon aperture.")
parser.add_argument(
"--save-png", action="store_true", help="non-interactive run: save to PNGs"
)
args = parser.parse_args()


# initial/final beam
series = io.Series("diags/openPMD/monitor.h5", io.Access.read_only)
last_step = list(series.iterations)[-1]
initial = series.iterations[1].particles["beam"].to_df()
final = series.iterations[last_step].particles["beam"].to_df()


f, axs = plt.subplots(1, 2, figsize=(8, 4), constrained_layout=True)

axs[0].scatter(initial["position_x"] * 1.0e3, initial["position_y"] * 1.0e3)
axs[0].set_title("initial")
axs[0].set_xlabel(r"$x$ [mm]")
axs[0].set_ylabel(r"$y$ [mm]")
axs[0].set_xlim([-5.5, 5.5])
axs[0].set_ylim([-5.5, 5.5])

axs[1].scatter(final["position_x"] * 1.0e3, final["position_y"] * 1.0e3)
axs[1].set_title("final")
axs[1].set_xlabel(r"$x$ [mm]")
axs[1].set_ylabel(r"$y$ [mm]")
axs[1].set_xlim([-5.5, 5.5])
axs[1].set_ylim([-5.3, 5.3])


plt.tight_layout()
if args.save_png:
plt.savefig("polygon_aperture.png")
else:
plt.show()
Loading
Loading