Aperture ======== This module describes the **aperture checking system** (Aperture) in PASS, used to check whether particles exceed the transverse aperture boundaries of the beam pipe during particle tracking. Aperture checking is a core component of beam loss simulation, capable of identifying and recording particles lost due to transverse coordinates exceeding physical pipe limits. The aperture module is located at ``PASS/utils/aperture.py`` and provides both CPU and GPU implementations (called via the ``check_aperture_cpu`` and ``check_aperture_gpu`` functions, respectively), automatically invoked after each element tracking. The current element's longitudinal position :math:`s` and the current turn number are passed in at call time. Aperture checking is performed only on the transverse coordinates :math:`(x, y)` of particles and does not involve longitudinal coordinates. Each element can independently set its aperture type and parameters, supporting 10 aperture geometries. Geometry construction and loss handling are both defined in this one file. ``build_aperture({"Type": ..., "Value": ...})`` constructs a geometry object; ``mask(x, y)`` includes the wall, while ``strict_mask(x, y)`` excludes it. These predicates accept NumPy or CuPy coordinate arrays and return a mask on the same backend without modifying particles. ``aperture_bounds(geometry)`` returns the geometric extents for initialization checks. ``check_aperture_gpu`` supports all types below with float32 or float64 particle coordinates and records losses on the device. It validates shape parameters before launching a CUDA kernel, accepts integer or floating-point dimensions, and does nothing for an empty bunch. Previously lost particles retain their original loss position and turn; particles outside the requested bunch range are untouched. CPU execution does not require CuPy. This GPU support concerns the aperture module; PIC and SpaceCharge tracking remain CPU-only. Interface Parameters -------------------- The aperture system is controlled by two parameters: .. list-table:: :header-rows: 1 :widths: 20 25 15 40 * - Property - JSON key - Type - Description * - ``aperture_type`` - ``Aperture Type`` - str - Aperture type, case-insensitive; available values are listed below * - ``aperture_value`` - ``Aperture Value`` - list - Aperture parameter values; meaning varies by type .. note:: ``aperture_type`` is case-insensitive and is internally converted to lowercase before matching. The ``off`` and ``default`` types ignore ``aperture_value`` . Lost Particle Handling ---------------------- Only strict aperture interiors survive on both CPU and GPU. Particles touching any physical wall are lost, including polygon edges and vertices; rectangular loss does not require both coordinates to reach their limits. When a particle is determined to be lost, the system performs the following operations: - **tag negation** : :math:`\text{tag} \leftarrow -|\text{tag}|` , preserving the particle ID information and only negating the sign to mark it as lost - **lost_position** : records the longitudinal coordinate :math:`s` of the loss location, i.e., the longitudinal position of the current element - **lost_turn** : records the turn number at the time of loss Particles already lost ( :math:`\text{tag} < 0` ) are skipped in subsequent aperture checks and are not marked again. Aperture checking is performed only on surviving particles ( :math:`\text{tag} > 0` ). Detailed Aperture Types ----------------------- The following describes the parameter definitions and loss conditions for each of the 10 aperture types. off (Disabled) ~~~~~~~~~~~~~~ **Parameters** : none ( ``aperture_value`` is ignored) **Description** : No aperture checking is performed; all particles are retained. .. raw:: html
x y OFF
default (Default Rectangle) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Parameters** : none ( ``aperture_value`` is ignored) **Description** : Ordinary elements use the default ±1m rectangle, equivalent to ``aperture_value = [1.0, 1.0]``. ``SpaceCharge`` instead resolves default to the rectangle defined by its configuration's grid extent; see :doc:`space_charge`. **Loss condition** : .. math:: |x| \ge 1.0 \quad \text{or} \quad |y| \ge 1.0 .. raw:: html
x y +1m -1m
circle (Circular) ~~~~~~~~~~~~~~~~~ **Parameters** : ``aperture_value = [r]`` , where :math:`r` is the circle radius. **Loss condition** : .. math:: x^2 + y^2 \ge r^2 .. raw:: html
x y r
rectangle (Rectangular) ~~~~~~~~~~~~~~~~~~~~~~~ **Parameters** : ``aperture_value = [w, h]`` , where :math:`w` is the half-width and :math:`h` is the half-height. **Loss condition** (particle is lost if either condition is met): .. math:: |x| \ge w .. math:: |y| \ge h .. raw:: html
x y w h
ellipse (Elliptical) ~~~~~~~~~~~~~~~~~~~~ **Parameters** : ``aperture_value = [a, b]`` , where :math:`a` is the semi-major axis (x direction) and :math:`b` is the semi-minor axis (y direction). **Loss condition** : .. math:: \left(\frac{x}{a}\right)^2 + \left(\frac{y}{b}\right)^2 \ge 1 .. raw:: html
x y a b
rectcircle (Rectangle Inscribed Circle) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Parameters** : ``aperture_value = [w, h, r]`` , where :math:`w` is the rectangle half-width, :math:`h` is the rectangle half-height, and :math:`r` is the circle radius. The aperture region is the **intersection** of the rectangle and the circle (particles must be inside both the rectangle and the circle to survive). **Loss condition** (particle is lost if either condition is met): .. math:: |x| \ge w \quad \text{or} \quad |y| \ge h .. math:: x^2 + y^2 \ge r^2 .. raw:: html
x y w h r
.. note:: The red dashed line is the rectangle boundary, and the blue solid line is the circle boundary. The aperture region is the intersection of the two. rectellipse (Rectangle Inscribed Ellipse) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Parameters** : ``aperture_value = [w, h, a, b]`` , where :math:`w` is the rectangle half-width, :math:`h` is the rectangle half-height, :math:`a` is the ellipse semi-major axis (x direction), and :math:`b` is the ellipse semi-minor axis (y direction). The aperture region is the **intersection** of the rectangle and the ellipse (particles must be inside both the rectangle and the ellipse to survive). **Loss condition** (particle is lost if either condition is met): .. math:: |x| \ge w \quad \text{or} \quad |y| \ge h .. math:: \left(\frac{x}{a}\right)^2 + \left(\frac{y}{b}\right)^2 \ge 1 .. raw:: html
x y w h a b
.. note:: The red dashed line is the rectangle boundary, and the blue solid line is the ellipse boundary. The aperture region is the intersection of the two. racetrack (Racetrack) ~~~~~~~~~~~~~~~~~~~~~ **Parameters** : ``aperture_value = [w, h, a, b]`` , where :math:`w` is the rectangle half-width, :math:`h` is the rectangle half-height, :math:`a` is the x-direction semi-axis of the elliptical ends, and :math:`b` is the y-direction semi-axis of the elliptical ends. The racetrack aperture consists of a central rectangle and two semi-elliptical ends. The centers of the elliptical ends are located at :math:`(\pm w, 0)` . **Survival condition** (particle survives if either condition is met): Strictly inside the rectangular region: .. math:: |x| < w \quad \text{and} \quad |y| < h Inside the elliptical end region (when :math:`|x| > w` ): .. math:: \left(\frac{|x| - w}{a}\right)^2 + \left(\frac{y}{b}\right)^2 < 1 At the internal seams :math:`|x|=w`, a particle survives only when :math:`|y|<\min(h,b)`; these seams are not physical walls. All other points outside the strict regions are lost. .. raw:: html
x y w h a b
.. note:: The orange dots mark the centers of the elliptical ends at :math:`(\pm w, 0)` . octagon (Octagonal) ~~~~~~~~~~~~~~~~~~~ **Parameters** : ``aperture_value = [w, h, d]`` , where :math:`w` is the half-width, :math:`h` is the half-height, and :math:`d` is the half-diagonal clearance (chamfer distance). The octagon is the shape obtained by cutting 45° corners off a rectangle. The larger :math:`d` , the larger the chamfer; when :math:`d = 0` , it degenerates into a rectangle. **Loss condition** (particle is lost if either condition is met): .. math:: |x| \ge w \quad \text{or} \quad |y| \ge h .. math:: |x| + |y| \ge w + h - d .. raw:: html
x y w h d
polygon (Polygon) ~~~~~~~~~~~~~~~~~ **Parameters** : ``aperture_value = [[x1, y1], [x2, y2], ...]`` , a list of vertices, automatically closed (the last vertex connects back to the first vertex). **Loss condition** : The point lies on an edge or vertex, or outside the polygon. The edge check precedes ray casting; it uses a small floating-point tolerance shared by CPU and GPU. The **ray casting** method is used to determine whether a point is inside the polygon: a ray is cast from the test point in the horizontal direction, and the number of intersections with the polygon edges is counted: - Odd number of intersections → the point is inside the polygon (survives) - Even number of intersections → the point is outside the polygon (lost) .. raw:: html
x y P1 P2 P3 P4 P5 P6
Parameter Summary Table ------------------------ .. list-table:: :header-rows: 1 :widths: 15 25 60 * - Type - aperture_value - Description * - ``off`` - ignored - No aperture checking * - ``default`` - ignored - Default ±1m rectangular aperture * - ``circle`` - ``[r]`` - Circular, :math:`r` is the radius * - ``rectangle`` - ``[w, h]`` - Rectangular, :math:`w` is the half-width, :math:`h` is the half-height * - ``ellipse`` - ``[a, b]`` - Elliptical, :math:`a` is the semi-major axis, :math:`b` is the semi-minor axis * - ``rectcircle`` - ``[w, h, r]`` - Intersection of rectangle and circle * - ``rectellipse`` - ``[w, h, a, b]`` - Intersection of rectangle and ellipse * - ``racetrack`` - ``[w, h, a, b]`` - Racetrack (rectangle + elliptical ends) * - ``octagon`` - ``[w, h, d]`` - Octagonal (rectangle with 45° chamfers) * - ``polygon`` - ``[[x1,y1], ...]`` - Polygon vertex list, automatically closed Usage Example ------------- The following JSON snippets show the configuration of each aperture type. Aperture parameters are element properties, placed alongside fields such as ``S (m)`` , ``Command`` , ``Length (m)`` , etc.: **Circular aperture** : .. code-block:: json "Drift1": { "S (m)": 10.0, "Command": "Drift", "Length (m)": 0.5, "Aperture Type": "circle", "Aperture Value": [0.1] } **Rectangular aperture** : .. code-block:: json "Drift2": { "S (m)": 10.5, "Command": "Drift", "Length (m)": 0.3, "Aperture Type": "rectangle", "Aperture Value": [0.06, 0.04] } **Elliptical aperture** : .. code-block:: json "Drift3": { "S (m)": 11.0, "Command": "Drift", "Length (m)": 0.2, "Aperture Type": "ellipse", "Aperture Value": [0.06, 0.04] } **Racetrack aperture** : .. code-block:: json "Drift4": { "S (m)": 11.5, "Command": "Drift", "Length (m)": 0.4, "Aperture Type": "racetrack", "Aperture Value": [0.03, 0.05, 0.02, 0.05] } **Octagonal aperture** : .. code-block:: json "Drift5": { "S (m)": 12.0, "Command": "Drift", "Length (m)": 0.3, "Aperture Type": "octagon", "Aperture Value": [0.05, 0.03, 0.01] } **Polygon aperture** : .. code-block:: json "Drift6": { "S (m)": 12.5, "Command": "Drift", "Length (m)": 0.2, "Aperture Type": "polygon", "Aperture Value": [[0.05, 0.0], [0.025, 0.043], [-0.025, 0.043], [-0.05, 0.0], [-0.025, -0.043], [0.025, -0.043]] } **Disable aperture checking** : .. code-block:: json "Drift7": { "S (m)": 13.0, "Command": "Drift", "Length (m)": 0.5, "Aperture Type": "off" }