Reference Manual
Imaging Atmospheric Cherenkov Telescopes
Classes:
|
A class to represent an Imaging Atmospheric Cherenkov Telescope (IACT). |
- class iactsim.IACT(optical_system, camera=None, position=(0., 0., 0.), pointing=(0, 0))
A class to represent an Imaging Atmospheric Cherenkov Telescope (IACT).
This class serves as a wrapper for a CUDA-accelerated backend. It handles the conversion of optical system and camera information into CuPy ndarrays (transferring data to the GPU), and arranges this data in a format suitable for input to the CUDA kernels that perform the actual simulation.
- Parameters:
optical_system (OpticalSystem) – An instance of a class derived from
OpticalSystemrepresenting the telescope optical system.camera (CherenkovCamera) – An instance of a class derived from
CherenkovCamerarepresenting the telescope Cherenkov camera.position (Tuple[float, float, float] | List[float] | numpy.ndarray) – The Cartesian coordinates (x, y, z) representing the telescope position in millimeters. Can be a tuple, list, or NumPy array.
pointing (Tuple[float, float] | List[float] | numpy.ndarray) – The horizontal coordinates (altitude, azimuth) representing the telescope pointing direction in degrees. Can be a tuple, list, or NumPy array.
- Raises:
If optical_system is not an instance of
OpticalSystemor a derived class. - If camera is not an instance ofCherenkovCameraor a derived class.
If position does not have 3 elements. - If pointing does not have 2 elements.
Attributes:
Telescope pointing altitude (0-90).
Telescope pointing azimuth (0-360).
The telescope Cherenkov camera.
The rotation matrix transforming the standard pointing frame into the telescope frame.
Compute the rotation matrix to transform from the local reference frame to the telescope reference frame.
The telescope optical system
The telescope pointing direction in horizontal coordinates (altitude, azimuth) in degrees.
The telescope position in Cartesian coordinates (x, y, z) in millimeters.
Methods:
clean_memory([reclaim])Clears GPU memory related to ray-tracing by removing references to CuPy arrays and freeing CuPy memory blocks.
Build and copy to device all the CUDA kernels input related to the optical configuration.
trace_photons(positions, directions, ...[, ...])Traces photons through the telescope optical system and optionally simulates the Cherenkov camera response.
visualize_ray_tracing(positions, directions, ...)Visualizes the ray tracing process by performing step-by-step propagation of photons.
- property camera: CherenkovCamera
The telescope Cherenkov camera.
- Type:
- clean_memory(reclaim=False)
Clears GPU memory related to ray-tracing by removing references to CuPy arrays and freeing CuPy memory blocks.
- Parameters:
reclaim (bool, optional) – If True, forces Python garbage collection before freeing blocks to ensure circular references are destroyed. This is a slow operation. Defaults to False.
- cuda_init()
Build and copy to device all the CUDA kernels input related to the optical configuration.
- property custom_rotation: ndarray
The rotation matrix transforming the standard pointing frame into the telescope frame.
\[R_{telescope} = R_{custom} \cdot R_{pointing}\]The pointing frame (when this matrix is identity) is defined such that when the telescope is pointing at the horizon towards the North (i.e. alt: 0, az: 0), the axes are aligned as follows:
z-axis: aligned with the telescope optical axis, pointing North.
x-axis: perpendicular to the optical axis, pointing downward.
y-axis: perpendicular to the optical axis, pointing west.
Example
The following rotates the telescope reference system in such a way to have, when the telescope is pointing at the horizon towards the North (i.e. alt: 0, az: 0), the axes aligned as follows:
z-axis: aligned with the telescope optical axis, pointing North.
y-axis: perpendicular to the optical axis, pointing downward.
x-axis: perpendicular to the optical axis, pointing west.
rotation = np.array([ [ 0, 1, 0], # new X is old Y [ 1, 0, 0], # new Y is old X [ 0, 0, 1] ]) telescope.custom_rotation = rotation
- Returns:
R – The 3x3 rotation matrix. Defaults to the Identity matrix (no offset).
- Return type:
ndarray, shape (3, 3)
- property local_to_telescope_rotation: ndarray
Compute the rotation matrix to transform from the local reference frame to the telescope reference frame.
- property optical_system: OpticalSystem
The telescope optical system
- Type:
- property pointing: ndarray
The telescope pointing direction in horizontal coordinates (altitude, azimuth) in degrees.
- Type:
- property position: ndarray
The telescope position in Cartesian coordinates (x, y, z) in millimeters.
- Type:
- trace_photons(positions, directions, wavelengths, arrival_times, emission_altitudes=None, weights=None, events_mapping=None, *, photons_per_bunch=1, unpack_wavelength_range=None, shift_to_z_level=None, transform_to_tel=True, simulate_camera=False, min_n_pes=1, get_camera_input=False, max_bounces=100, save_last_bounce=False, seed=None, free_memory_at_end=False)
Traces photons through the telescope optical system and optionally simulates the Cherenkov camera response.
This method simulates the propagation of photons through an optical system, taking into account their initial positions, directions, wavelengths, and arrival times. Each element in the input arrays can represent either a single photon or a “bunch” of photons. The
photons_per_bunchparameter determines how many photons are represented by each element. Ifphotons_per_bunch> 1, it is assumed that all photons within a bunch share the same initial position, direction and arrival time (for the wavelength seeunpack_wavelength_range).It can optionally:
geometrically shift photon bunches to a specific Z-coordinate plane using the shift_bunches_position kernel (this is needed, for example, when processing CORSIKA output since photon bunches are stored at the telescope observational level, i.e., z=0);
generate and assign individual wavelengths using the Cherenkov emission spectrum. The generate_bunch_wavelengths kernel is only used if a wavelength range is provided and the existing wavelength is 0. The unpack_bunches kernel will also generate wavelengths, but without checking the initial wavelength value, and it will unpack the bunches into individual photons;
model the effects of atmospheric transmission based on emission altitudes;
simulate the Cherenkov camera response.
- Parameters:
positions (Union[numpy.ndarray, cp.ndarray] of shape (N, 3)) – Initial Cartesian coordinates (x, y, z) of the photon bunches in millimeters (mm). Must be either a NumPy (CPU) or CuPy (GPU) array.
directions (Union[numpy.ndarray, cp.ndarray] of shape (N, 3)) – Initial direction vectors (vx, vy, vz) of the photon bunches. These should be normalized. Must be either a NumPy (CPU) or CuPy (GPU) array.
wavelengths (Union[numpy.ndarray, cp.ndarray] of shape (N,)) – Wavelengths of the photon bunches in nanometers (nm). Must be either a NumPy (CPU) or CuPy (GPU) array.
arrival_times (Union[numpy.ndarray, cp.ndarray] of shape (N,)) – Arrival times of the photon bunches at their respective positions in nanoseconds (ns). Must be either a NumPy (CPU) or CuPy (GPU) array.
emission_altitudes (Optional[Union[numpy.ndarray, cp.ndarray]], optional) – Emission altitudes of the photon bunches in millimeters (mm). This is used to calculate atmospheric transmission effects if enabled. Must be either a NumPy (CPU) or CuPy (GPU) array.
weights (Optional[Union[numpy.ndarray, cp.ndarray]], optional) – Weights of the photon bunches. The meaning of the weights depends on whether the bunches are unpacked or not (see Notes).
events_mapping (numpy.ndarray or list) – A NumPy array of shape (N+1,) to split the photons in to groups corresponding to N different events when generating the camera input arrays.
events_mapping[i]indicates the starting index inpositionsfor the i-th event.events_mapping[i+1]indicates the ending index (exclusive) inpositionsfor the i-th event. Therefore, photons belonging to event i are located inpositions[events_mapping[i]:events_mapping[i+1], :]. The last element of events_mapping must be equal to the number of photons.photons_per_bunch (int, optional) – Number of photons represented by each element in the input arrays. If 1, each element represents a single photon. If > 1, each element represents a bunch of photons that share the same properties, by default 1. Maximum value is 65535.
unpack_wavelength_range (tuple, optional) – Defines the (min, max) wavelength range in nm to sample from when assigning wavelengths to photons. If photons_per_bunch > 1, bunches are unpacked into individual photons and wavelengths are generated using the unpack_bunches kernel. If photons_per_bunch == 1, the generate_bunch_wavelengths kernel is used to assign Cherenkov-distributed wavelengths to the arrays in-place if the wavelength is 0. If None, no wavelength generation or unpacking occurs. By default None.
shift_to_z_level (float, optional) – If not None, invokes the shift_bunches_position kernel to project the initial positions of the bunches to the given Z-coordinate plane (in mm) along their direction vectors. The arrival times are automatically updated taking into account the distance traveled and the refractive index of air (Materials.AIR) for each photon specific wavelength. By default None.
transform_to_tel (bool, optional) – Whether to move detected photons into the telescope refrence frame or in the detector(s) reference frame. By default True.
simulate_camera (bool, optional) – Whether to simulate the response of the telescope Cherenkov camera.
min_n_pes (int, optional) – Minimum number of photo-electrons needed to trigger a camera simulation (if
simulate_camerais True). By default 1.get_camera_input (bool, optional) – Whether to return the input for camera simulation (i.e. photon arrival times for each pixel) as CuPy ndarrays. By default False.
max_bounces (int, optional) – Maximum number of bounces before the photon is killed. By default 100.
save_last_bounce (float, optional) – Keep the position at the last bounce. Only for ray tracing visualization. By default False.
seed (int, optional) – Base seed of the simulation. If None a random seed will be used. By default None.
free_memory_at_end (bool, optional) – Whether to clear memory and drop references to the internal device arrays at the conclusion of the ray-tracing (it simply calls clean_memory(reclaim=False)). By default False.
- Returns:
ndarray – List of triggered events index. If
simulate_camerais True andget_camera_inputis False.tuple(cp.ndarray, cp.ndarray) – Input CuPy arrays for
CherenkovCamera.simulate_response()method. Ifsimulate_camerais False andget_camera_inputis True.tuple(cp.ndarray, cp.ndarray, np.ndarray) – Input CuPy arrays for
CherenkovCamera.simulate_response()method and the list of triggered events index. Ifsimulate_camerais True andget_camera_inputis True.
Warning
Telescope configuration must be copied into the device before calling this method. Use the
cuda_init()method.Warning
The ray-tracing operates with positions in mm, wavelengths in nm, and times in ns. It also handles photon bunches, where each thread may process multiple photons if
photons_per_bunch> 1. In this case is assumed that each element of the input arrays represents a bunch of photons that share the same initial position, direction, wavelength, and arrival time. The arrays will maintain this structure, with each element representing the updated properties of a photon bunch.To treat each photon in a bunch separately during the simulation, the
unpack_wavelength_rangeparameter must be provided. Ifunpack_wavelength_rangeis not None, each bunch will be unpacked into its constituent photons, and the wavelength of each photon will be randomly generated within the specified range following a Cherenkov-like distribution.The valid range and meaning of the
weightsarray depends on this unpacking behavior:If
unpack_wavelength_rangeis provided, the weight of an input element represents the sum of the weights of the photons within that bunch. Therefore, it must be <=photons_per_bunch;If
unpack_wavelength_rangeis not provided, the weight applies to the bunch as a whole single entity, and must be <= 1.
Warning
The input arrays can be either CuPy or NumPy ndarray. In the former case arrays are modified in place. In the latter case the arrays are copied to the device and can be accessed through the following attributes:
self._d_directions
self._d_positions
self._d_wavelengths
self._d_arrival_times
self._d_emission_altitudes
self._d_weights
Warning
To avoid severe VRAM fragmentation when processing several sources repeatedly in a loop (such as large batches of CORSIKA files), you should call this method with
free_memory_at_end=True. Failing to do so can cause CuPy memory pool to bloat with arrays of varying sizes, eventually resulting in silent illegal address errors.Notes
Memory Usage
The peak GPU memory (VRAM) footprint depends on the simulation flags provided and whether photon bunches are unpacked (i.e.,
unpack_wavelength_rangeis not None):Ray tracing only (
simulate_camera=Falseandget_camera_input=False): The method only allocates the base arrays for photon propagation. Peak VRAM (Bytes):Packed simulation: ≈ \(44N\)
Unpacked simulation: ≈ \(44NW + 32N\)
SiPM camera simulation without micro-cells (
camera.simulate_ucells=False): Filters detected photons, sorts them, and generates the time expansion array. Peak VRAM (Bytes):Packed simulation: ≈ \(45N + 64M + 4P\)
Unpacked simulation: ≈ \(45NW + 64M + 4P + 32N\)
SiPM camera simulation with micro-cells (
camera.simulate_ucells=True): Adds an additional output array to track the specific sub-pixel IDs during expansion. Peak VRAM (Bytes):Packed simulation: ≈ \(45N + 64M + 8P\)
Unpacked simulation: ≈ \(45NW + 64M + 8P + 32N\)
The formulas above assume the optional
weightsandemission_altitudesparameters are not provided. If provided, each array adds 4 bytes per tracked element (\(4N\) for packed, or + \(4NW\) for unpacked).Where:
\(N\) is the total number of input photon bunches;
\(W\) is the
photons_per_bunchmultiplier;\(M\) is the number of detected elements (photons or bunches);
\(P\) is the total number of photo-electrons generated after weight expansion (\(P \ge M\)).
Example Assuming a telescope optical efficiency of 10% (\(M = 0.1N\)) and a bunch weight of 5 photons per bunch (\(W = 5\)), and providing both
weightsandemission_altitudes, the peak VRAM scales as follows:Packed execution (Packed into bunches, \(N_{sim} = N\), \(P = 5M\)):
Input bunches (N)
Ray tracing only
w/o microcells
w/ microcells
1,000,000
~ 52.0 MB
~ 61.4 MB
~ 63.4 MB
5,000,000
~ 260.0 MB
~ 307.0 MB
~ 317.0 MB
10,000,000
~ 520.0 MB
~ 614.0 MB
~ 634.0 MB
25,000,000
~ 1300.0 MB
~ 1535.0 MB
~ 1585.0 MB
Unpacked execution (Unpacked into single photons, \(N_{sim} = 5N\), \(P = M\)):
Input bunches (N)
Ray tracing only
w/o microcells
w/ microcells
1,000,000
~ 292.0 MB
~ 331.0 MB
~ 333.0 MB
5,000,000
~ 1460.0 MB
~ 1655.0 MB
~ 1665.0 MB
10,000,000
~ 2920.0 MB
~ 3310.0 MB
~ 3330.0 MB
25,000,000
~ 7300.0 MB
~ 8275.0 MB
~ 8325.0 MB
- visualize_ray_tracing(positions, directions, wavelengths, arrival_times, emission_altitudes=None, weights=None, photons_per_bunch=1, unpack_wavelength_range=None, shift_to_z_level=None, *, show_not_detected=True, map_wavelength_color=True, get_renderer=False, opacity=None, show_hits=True, show_rays=True, point_size=1, orthographic=False, focal_point=None, resolution=None, max_bounces=100)
Visualizes the ray tracing process by performing step-by-step propagation of photons.
This method initializes a VTK renderer and iteratively calls trace_photons with max_bounces=1 to capture and visualize the path of photons between surfaces.
- Parameters:
positions (Union[numpy.ndarray, cp.ndarray] of shape (N, 3)) – Initial Cartesian coordinates (x, y, z) of the photon bunches in millimeters (mm). Must be either a NumPy (CPU) or CuPy (GPU) array.
directions (Union[numpy.ndarray, cp.ndarray] of shape (N, 3)) – Initial direction vectors (vx, vy, vz) of the photon bunches. These should be normalized. Must be either a NumPy (CPU) or CuPy (GPU) array.
wavelengths (Union[numpy.ndarray, cp.ndarray] of shape (N,)) – Wavelengths of the photon bunches in nanometers (nm). Must be either a NumPy (CPU) or CuPy (GPU) array.
arrival_times (Union[numpy.ndarray, cp.ndarray] of shape (N,)) – Arrival times of the photon bunches at their respective positions in nanoseconds (ns). Must be either a NumPy (CPU) or CuPy (GPU) array.
emission_altitudes (Optional[Union[numpy.ndarray, cp.ndarray]], optional) – Emission altitudes of the photon bunches in millimeters (mm). This is used to calculate atmospheric transmission effects if enabled. Must be either a NumPy (CPU) or CuPy (GPU) array.
weights (Optional[Union[numpy.ndarray, cp.ndarray]], optional) – Weights of the photon bunches. The meaning of the weights depends on whether the bunches are unpacked or not (see
trace_photons()).photons_per_bunch (int, optional) – Number of physical photons represented by one simulated photon. Defaults to 1.
unpack_wavelength_range (tuple, optional) – Defines in which range (min,max) generate the wavelength of each unpacked photon. If None, bunches are non unpacked. By default None.
shift_to_z_level (float, optional) – If not None, invokes the shift_bunches_position kernel to geometrically project the initial positions of the bunches to the given Z-coordinate plane (in mm) along their direction vectors. The arrival times are automatically updated taking into account the distance traveled and the refractive index of air for each photon specific wavelength. By default None.
show_not_detected (bool, optional) – Whether to show also photons that are not detected by the camera. Defaults to True.
map_wavelength_color (bool, optional) – Whether to color rays based on their wavelength. Defaults to True.
get_renderer (bool, optional) – If True, returns the VTKOpticalSystem instance instead of starting the render loop immediately. Defaults to False.
opacity (float, optional) – Opacity of the ray lines (0.0 to 1.0). If None, it is calculated based on the number of photons. Defaults to None.
show_hits (bool, optional) – Whether to render points at the location where rays intersect surfaces. Defaults to True.
show_rays (bool, optional) – Whether to render lines representing the photon paths. Defaults to True.
point_size (int, optional) – Size of the points rendered at intersection hits. Defaults to 1.
orthographic (bool, optional) – If True, start with a parallel projection. If False, start with a Perspective projection. Default is False.
focal_point (tuple, list, or str, optional) – If tuple/list: (x, y, z) coordinates to look at. If str: The name of the surface in self.os to look at. If None: Defaults to center of system.
resolution (float, optional) – Objects mesh resolution (in mm). By default None (depends on object extent).
max_bounces (int, optional) – Stop the ray-tracing if the number of bounces exceeds this value. Defaults to 100.
- Returns:
Returns the renderer instance if get_renderer is True, otherwise returns None after the render window is closed.
- Return type:
VTKOpticalSystem or None
optics
Classes:
|
Enumeration representing the possible shapes of an aperture. |
|
Represents an aspherical optical surface. |
|
Represents atmospheric optical depth as a function of photon wavelength and emission altitude. |
|
Represents a box optical surface. |
|
Extracts and defines the geometry of a camera system from an IACT object. |
|
Represents a truncated conical optical surface. |
|
Represents a cylindrical optical surface. |
|
Represents a flat optical surface. |
Handles the calculation and population of SurfaceProperties objects based on Fresnel equations for a given Surface instance. |
|
|
Represents a generic flat module with arbitrarily placed pixels. |
|
Represents a single pixel to be placed in a GenericFlatModule. |
A collection of Material instances with refractive index data (wavelength in nm). |
|
|
A class to handle dispersive Transfer Matrix Method (TMM) simulations using the tmm_fast backend, with a dynamic material database. |
|
Represents a generic optical system. |
|
Holds the texture object and metadata for refractive index lookups. |
|
Enumeration representing different types of sensor surfaces. |
|
A simulator for calculating the Photon Detection Efficiency (PDE) of Silicon Photomultipliers (SiPMs) given a coating stack. |
|
Represents a SiPM tile of NxN pixels. |
|
Represents a spherical optical surface. |
|
Represents surface transmittance, reflectance, absorption and detection efficiency as a function of photon wavelength and incidence angle. |
|
Enumeration representing different types of surface shapes. |
|
Container for GPU texture objects (optical + efficiency) and the metadata required to map physical values (wavelength, angle) to texture coordinates. |
|
Enumeration representing the different types of optical surfaces. |
|
Stores visualization attributes for an optical surface. |
- class iactsim.optics.ApertureShape(*values)
Enumeration representing the possible shapes of an aperture.
Methods:
__contains__(value)Return True if value is in cls.
__getitem__(name)Return the member matching name.
__iter__()Return members in definition order.
__len__()Return the number of members (no aliases)
- classmethod __contains__(value)
Return True if value is in cls.
value is in cls if: 1) value is a member of cls, or 2) value is the value of one of the cls’s members.
- classmethod __getitem__(name)
Return the member matching name.
- classmethod __iter__()
Return members in definition order.
- classmethod __len__()
Return the number of members (no aliases)
- class iactsim.optics.AsphericalSurface(half_aperture, curvature, conic_constant, aspheric_coefficients, central_hole_half_aperture=0.0, aperture_shape=ApertureShape.CIRCULAR, central_hole_shape=ApertureShape.CIRCULAR, is_fresnel=False, surface_type=SurfaceType.REFLECTIVE, position=np.array([0., 0., 0.]), tilt_angles=np.array([0., 0., 0.]), scattering_dispersion=0.0, properties=None, material_in=Materials.AIR, material_out=Materials.AIR, name=None)
Represents an aspherical optical surface.
- Parameters:
half_aperture (float) – Half-aperture of the surface.
curvature (float) – Surface curvature (1/radius of curvature)
conic_constant (float) – Conic constant
aspheric_coefficients (array-like) – Array of aspheric coefficients
central_hole_half_aperture (float, optional) – Half-aperture of the central hole (0.0 if no hole), by default 0.0
aperture_shape (ApertureShape, optional) – Shape of the aperture (circular, hexagonal or rectangular), by default ApertureShape.CIRCULAR
central_hole_shape (ApertureShape, optional) – Shape of the central hole (circular, hexagonal or rectangular), by default ApertureShape.CIRCULAR
is_fresnel (bool, optional) – Whether the surface is an ideal Fresnel lens/mirror, by default False
surface_type (SurfaceType, optional) – Type of surface (reflective, refractive, opaque, dummy), by default SurfaceType.REFLECTIVE
position (array-like, optional) – Position of the surface center [x, y, z], by default None
tilt_angles (array-like, optional) – Tilt angles (counter-clockwise x-tilt, y-tilt and z_tilt) in degrees, by default no tilt.
scattering_dispersion (float, optional) – Standard deviation of Gaussian scattering after reflection/transmission, by default 0.0
properties (SurfaceProperties, optional) – Reflectance/transmittance properties of the surface, by default None
material_in (material, optional) – Material of the space before the surface front side. I.e. the material in which photons arriving with a negative z-component of their direction vector are travelling, by default standard air.
material_out (material, optional) – Material of the space after the surface back side. I.e. the material in which photons arriving with a positive z-component of their direction vector are travelling, by default standard air.
name (str, optional) – Surface name
Methods:
__repr__()Returns a string representation of the surface object.
__str__()Returns a string representation of the surface object formatted as a table.
Returns the surface properties packed into a structured NumPy record.
Calculates the 3D rotation matrix to transform into the surface reference system from the telescope reference system.
Calculate the upward-going normal unit vector at a given surface point (x,y) in the surface reference frame.
sagitta(r)Calculate the sagitta of the aspheric surface at a given radial distance in the surface refrence frame.
set_rotation_matrix(a_matrix)Set a custom rotation matrix instead of deriving it from tilt angles.
Attributes:
Treat the surface as a segment centered at these aperture coordinates.
- __str__()
Returns a string representation of the surface object formatted as a table.
- Return type:
- get_cuda_record()
Returns the surface properties packed into a structured NumPy record.
- Return type:
- get_rotation_matrix()
Calculates the 3D rotation matrix to transform into the surface reference system from the telescope reference system.
The computation is based on surface tilt angles and assumes rotations are applied in the order (last first) Z @ Y @ X. This corresponds to rotating the surface around the telescope X axis, then the telescope Y axis and finally the telescope Z axis. The rotations follow the right-hand rule (counter-clockwise).
These angles are intended for small misalignments, while
create_surface_rotation()is a more robust method. Tilt angles can be bypassed if a custom rotation matrix has been set usingset_rotation_matrix()method.Tilt angles are expected in degrees.
- Return type:
- Returns:
np.ndarray: A 3x3 rotation matrix. The returned matrix is the transpose of the tilt sequence. It transforms from the telescope reference system into the surface reference system.
- get_surface_normal_vector(x, y)
Calculate the upward-going normal unit vector at a given surface point (x,y) in the surface reference frame.
- offset
Treat the surface as a segment centered at these aperture coordinates.
- sagitta(r)
Calculate the sagitta of the aspheric surface at a given radial distance in the surface refrence frame.
- Parameters:
r (np.ndarray, list or scalar) – Radial distance(s) from the optical axis.
- Returns:
Sagitta value(s) at the given radial distance(s).
- Return type:
np.ndarray
- set_rotation_matrix(a_matrix)
Set a custom rotation matrix instead of deriving it from tilt angles. To use tilt angles set it to
None.- Parameters:
a_matrix (np.ndarray) – 3D rotation matrix to transform from telescope to surface reference frame.
- class iactsim.optics.AtmosphericTransmission(info='', value=None, wavelength=None, altitude=None)
Represents atmospheric optical depth as a function of photon wavelength and emission altitude.
- info
A string containing the header/metadata from the loaded configuration file.
- value
A numpy.ndarray of shape (m,n) representing the atmosphere optical depth (tau).
- wavelength
A numpy.ndarray of shape (n,) representing the wavelengths in nanometers.
- altitude
A numpy.ndarray of shape (m,) representing the emission altitude in millimeters.
Methods:
load_simtel_file(filepath)Loads atmospheric optical depth data from a simtel atmospheric transimission input file.
- classmethod load_simtel_file(filepath)
Loads atmospheric optical depth data from a simtel atmospheric transimission input file. Automatically extracts header info and converts emission altitudes from km to mm.
- class iactsim.optics.BoxSurface(half_side_x, half_side_y, half_side_z, has_top=True, has_bottom=True, position=np.array([0., 0., 0.]), tilt_angles=np.array([0., 0., 0.]), surface_type=SurfaceType.OPAQUE, name=None)
Represents a box optical surface.
- Parameters:
half_side_x (float) – Half-side of the box in the x-direction.
half_side_y (float) – Half-side of the box in the y-direction.
half_side_z (float) – Half-side of the box in the z-direction.
has_top (bool, optional) – Whether the box has a top cap, by default True.
has_bottom (bool, optional) – Whether the box has a bottom cap, by default True.
position (array-like, optional) – Position of box center [x, y, z], by default (0,0,0).
tilt_angles (array-like, optional) – Tilt angles (counter-clockwise x-tilt, y-tilt and z_tilt) in degrees, by default no tilt.
surface_type (SurfaceType, optional) – Type of surface (opaque or sensitive), by default SurfaceType.OPAQUE.
name (str, optional) – Surface name
Methods:
__repr__()Returns a string representation of the surface object.
__str__()Returns a string representation of the surface object formatted as a table.
Returns the surface properties packed into a structured NumPy record.
Calculates the 3D rotation matrix to transform into the surface reference system from the telescope reference system.
set_rotation_matrix(a_matrix)Set a custom rotation matrix instead of deriving it from tilt angles.
- __str__()
Returns a string representation of the surface object formatted as a table.
- Return type:
- get_cuda_record()
Returns the surface properties packed into a structured NumPy record.
- Return type:
- get_rotation_matrix()
Calculates the 3D rotation matrix to transform into the surface reference system from the telescope reference system.
The computation is based on surface tilt angles and assumes rotations are applied in the order (last first) Z @ Y @ X. This corresponds to rotating the surface around the telescope X axis, then the telescope Y axis and finally the telescope Z axis. The rotations follow the right-hand rule (counter-clockwise).
These angles are intended for small misalignments, while
create_surface_rotation()is a more robust method. Tilt angles can be bypassed if a custom rotation matrix has been set usingset_rotation_matrix()method.Tilt angles are expected in degrees.
- Return type:
- Returns:
np.ndarray: A 3x3 rotation matrix. The returned matrix is the transpose of the tilt sequence. It transforms from the telescope reference system into the surface reference system.
- set_rotation_matrix(a_matrix)
Set a custom rotation matrix instead of deriving it from tilt angles. To use tilt angles set it to
None.- Parameters:
a_matrix (np.ndarray) – 3D rotation matrix to transform from telescope to surface reference frame.
- class iactsim.optics.CameraGeometry(telescope)
Extracts and defines the geometry of a camera system from an IACT object.
This class handles multiple camera modules (e.g., SipmTileSurface and GenericFlatModule) that make up the focal plane. It calculates the 3D position of all pixels in the telescope reference system and organizes the data into dictionaries for efficient lookup.
- Parameters:
telescope (IACT) – An instance of the IACT telescope containing the optical system and camera.
- pixels
A dictionary mapping pixel ID to a dictionary of its properties:
‘position’: numpy.ndarray of shape (3,) representing the [x, y, z] coordinates in the telescope reference system.
‘half_size’: float representing the half-size of the pixel.
‘shape’: ApertureShape representing the shape of the pixel.
‘module_id’: int representing the ID of the module it belongs to.
- Type:
- modules
A dictionary mapping module ID to a dictionary of its properties:
‘type’: str representing the sensor type (‘SIPM_TILE’ or ‘GENERIC_FLAT_MODULE’).
‘pixel_ids’: list of int representing the IDs of the pixels in this module.
- Type:
Methods:
plot_layout([show_ids, ids_fontsize, ...])Plots the 2D camera x-y layout in the telescope reference system.
- plot_layout(show_ids=True, ids_fontsize=6., auto_adjust=True, ax=None)
Plots the 2D camera x-y layout in the telescope reference system.
- Parameters:
show_ids (bool, optional) – If True, displays the pixel ID at the center of each pixel. Defaults to True.
ids_fontsize (float, optional) – The font size for the pixel ID text. Defaults to 6.0.
auto_adjust (bool, optional) – If True, dynamically scales the figure size and adjusts the drawn pixel separation to prevent visual clumping. Defaults to True.
ax (matplotlib.axes.Axes, optional) – The axis on which to plot. If None, a new figure and axis are created.
- Returns:
The axis containing the plot.
- Return type:
- class iactsim.optics.ConicalSurface(radius_top, radius_bottom, height, has_top=True, has_bottom=True, position=np.array([0., 0., 0.]), tilt_angles=np.array([0., 0., 0.]), surface_type=SurfaceType.OPAQUE, name=None)
Represents a truncated conical optical surface.
- Parameters:
radius_top (float) – Top radius of the cone.
radius_bottom (float) – Bottom radius of the cone.
height (float) – Height of the conde.
has_top (bool, optional) – Whether the cone has a top cap, by default True.
has_bottom (bool, optional) – Whether the cone has a bottom cap, by default True.
position (array-like, optional) – Position of cone center [x, y, z] (half-height on the cone axis), by default (0,0,0).
tilt_angles (array-like, optional) – Tilt angles (counter-clockwise x-tilt, y-tilt and z_tilt) in degrees, by default no tilt.
surface_type (SurfaceType, optional) – Type of surface (opaque or sensitive), by default SurfaceType.OPAQUE.
name (str, optional) – Surface name
Methods:
__repr__()Returns a string representation of the surface object.
__str__()Returns a string representation of the surface object formatted as a table.
Returns the surface properties packed into a structured NumPy record.
Calculates the 3D rotation matrix to transform into the surface reference system from the telescope reference system.
set_rotation_matrix(a_matrix)Set a custom rotation matrix instead of deriving it from tilt angles.
- __str__()
Returns a string representation of the surface object formatted as a table.
- Return type:
- get_cuda_record()
Returns the surface properties packed into a structured NumPy record.
- Return type:
- get_rotation_matrix()
Calculates the 3D rotation matrix to transform into the surface reference system from the telescope reference system.
The computation is based on surface tilt angles and assumes rotations are applied in the order (last first) Z @ Y @ X. This corresponds to rotating the surface around the telescope X axis, then the telescope Y axis and finally the telescope Z axis. The rotations follow the right-hand rule (counter-clockwise).
These angles are intended for small misalignments, while
create_surface_rotation()is a more robust method. Tilt angles can be bypassed if a custom rotation matrix has been set usingset_rotation_matrix()method.Tilt angles are expected in degrees.
- Return type:
- Returns:
np.ndarray: A 3x3 rotation matrix. The returned matrix is the transpose of the tilt sequence. It transforms from the telescope reference system into the surface reference system.
- set_rotation_matrix(a_matrix)
Set a custom rotation matrix instead of deriving it from tilt angles. To use tilt angles set it to
None.- Parameters:
a_matrix (np.ndarray) – 3D rotation matrix to transform from telescope to surface reference frame.
- class iactsim.optics.CylindricalSurface(radius, height, has_top=True, has_bottom=True, position=np.array([0., 0., 0.]), tilt_angles=np.array([0., 0., 0.]), surface_type=SurfaceType.OPAQUE, name=None)
Represents a cylindrical optical surface.
- Parameters:
radius (float) – Radius of the cylinder.
height (float) – Height of the cylinder.
has_top (bool, optional) – Whether the cylinder has a top cap, by default True.
has_bottom (bool, optional) – Whether the cylinder has a bottom cap, by default True.
position (array-like, optional) – Position of cylinder center [x, y, z] (half-height on the cylinder axis), by default (0,0,0).
tilt_angles (array-like, optional) – Tilt angles (counter-clockwise x-tilt, y-tilt and z_tilt) in degrees, by default no tilt.
surface_type (SurfaceType, optional) – Type of surface (opaque or sensitive), by default SurfaceType.OPAQUE.
name (str, optional) – Surface name
Methods:
__repr__()Returns a string representation of the surface object.
__str__()Returns a string representation of the surface object formatted as a table.
Returns the surface properties packed into a structured NumPy record.
Calculates the 3D rotation matrix to transform into the surface reference system from the telescope reference system.
set_rotation_matrix(a_matrix)Set a custom rotation matrix instead of deriving it from tilt angles.
- __str__()
Returns a string representation of the surface object formatted as a table.
- Return type:
- get_cuda_record()
Returns the surface properties packed into a structured NumPy record.
- Return type:
- get_rotation_matrix()
Calculates the 3D rotation matrix to transform into the surface reference system from the telescope reference system.
The computation is based on surface tilt angles and assumes rotations are applied in the order (last first) Z @ Y @ X. This corresponds to rotating the surface around the telescope X axis, then the telescope Y axis and finally the telescope Z axis. The rotations follow the right-hand rule (counter-clockwise).
These angles are intended for small misalignments, while
create_surface_rotation()is a more robust method. Tilt angles can be bypassed if a custom rotation matrix has been set usingset_rotation_matrix()method.Tilt angles are expected in degrees.
- Return type:
- Returns:
np.ndarray: A 3x3 rotation matrix. The returned matrix is the transpose of the tilt sequence. It transforms from the telescope reference system into the surface reference system.
- set_rotation_matrix(a_matrix)
Set a custom rotation matrix instead of deriving it from tilt angles. To use tilt angles set it to
None.- Parameters:
a_matrix (np.ndarray) – 3D rotation matrix to transform from telescope to surface reference frame.
- class iactsim.optics.FlatSurface(half_aperture, central_hole_half_aperture=0.0, aperture_shape=ApertureShape.CIRCULAR, central_hole_shape=ApertureShape.CIRCULAR, surface_type=SurfaceType.REFLECTIVE, position=np.array([0., 0., 0.]), tilt_angles=np.array([0., 0., 0.]), scattering_dispersion=0.0, properties=None, material_in=Materials.AIR, material_out=Materials.AIR, name=None)
Represents a flat optical surface.
- Parameters:
half_aperture (float) – Half-aperture of the surface.
central_hole_half_aperture (float, optional) – Half-aperture of the central hole (0.0 if no hole), by default 0.0
aperture_shape (ApertureShape, optional) – Shape of the aperture (circular, hexagonal or rectangular), by default ApertureShape.CIRCULAR
central_hole_shape (ApertureShape, optional) – Shape of the central hole (circular, hexagonal or rectangular), by default ApertureShape.CIRCULAR
surface_type (SurfaceType, optional) – Type of surface (reflective, refractive, opaque, dummy), by default SurfaceType.REFLECTIVE
position (array-like, optional) – Position of the surface center [x, y, z], by default None
tilt_angles (array-like, optional) – Tilt angles (counter-clockwise x-tilt, y-tilt and z_tilt) in degrees, by default no tilt.
scattering_dispersion (float, optional) – Standard deviation of Gaussian scattering after reflection/transmission, by default 0.0
properties (SurfaceProperties, optional) – Reflectance/transmittance properties of the surface, by default None
material_in (material, optional) – Material of the space before the surface front side. I.e. the material in which photons arriving with a negative z-component of their direction vector are travelling, by default standard air.
material_out (material, optional) – Material of the space after the surface back side. I.e. the material in which photons arriving with a positive z-component of their direction vector are travelling, by default standard air.
name (str, optional) – Surface name
Methods:
__repr__()Returns a string representation of the surface object.
__str__()Returns a string representation of the surface object formatted as a table.
Returns the surface properties packed into a structured NumPy record.
Calculates the 3D rotation matrix to transform into the surface reference system from the telescope reference system.
Calculate the upward-going normal unit vector at a given surface point (x,y) in the surface reference frame.
sagitta(r)Calculate the sagitta of the aspheric surface at a given radial distance in the surface refrence frame.
set_rotation_matrix(a_matrix)Set a custom rotation matrix instead of deriving it from tilt angles.
Attributes:
Treat the surface as a segment centered at these aperture coordinates.
- __str__()
Returns a string representation of the surface object formatted as a table.
- Return type:
- get_cuda_record()
Returns the surface properties packed into a structured NumPy record.
- Return type:
- get_rotation_matrix()
Calculates the 3D rotation matrix to transform into the surface reference system from the telescope reference system.
The computation is based on surface tilt angles and assumes rotations are applied in the order (last first) Z @ Y @ X. This corresponds to rotating the surface around the telescope X axis, then the telescope Y axis and finally the telescope Z axis. The rotations follow the right-hand rule (counter-clockwise).
These angles are intended for small misalignments, while
create_surface_rotation()is a more robust method. Tilt angles can be bypassed if a custom rotation matrix has been set usingset_rotation_matrix()method.Tilt angles are expected in degrees.
- Return type:
- Returns:
np.ndarray: A 3x3 rotation matrix. The returned matrix is the transpose of the tilt sequence. It transforms from the telescope reference system into the surface reference system.
- get_surface_normal_vector(x, y)
Calculate the upward-going normal unit vector at a given surface point (x,y) in the surface reference frame.
- offset
Treat the surface as a segment centered at these aperture coordinates.
- sagitta(r)
Calculate the sagitta of the aspheric surface at a given radial distance in the surface refrence frame.
- Parameters:
r (np.ndarray, list or scalar) – Radial distance(s) from the optical axis.
- Returns:
Sagitta value(s) at the given radial distance(s).
- Return type:
np.ndarray
- set_rotation_matrix(a_matrix)
Set a custom rotation matrix instead of deriving it from tilt angles. To use tilt angles set it to
None.- Parameters:
a_matrix (np.ndarray) – 3D rotation matrix to transform from telescope to surface reference frame.
- class iactsim.optics.FresnelSurfacePropertiesGenerator
Handles the calculation and population of SurfaceProperties objects based on Fresnel equations for a given Surface instance.
Methods:
generate(surface[, wavelengths, angles, ...])Generate a populated SurfaceProperties object.
- generate(surface, wavelengths=None, angles=None, polarization='unpolarized', inplace=False)
Generate a populated SurfaceProperties object.
- Parameters:
surface (iactsim.optics.Surface) – The surface object containing material_in and material_out attributes, which must have get_refractive_index(wavelengths) methods.
wavelengths (np.ndarray, optional) – 1D array of wavelengths in nm. If None, defaults to np.arange(200, 901, 1).
angles (np.ndarray, optional) – 1D array of incidence angles in degrees. If None, defaults to np.arange(0, 91, 1).
polarization ({'unpolarized', 's', 'p', 'rs', 'rp'}, optional) – The specific polarization to compute for reflectance and transmittance. Default is ‘unpolarized’.
inplace (bool, optional) – If True, modifies the provided surface properties in place. Default is False.
- Returns:
If inplace is False, a populated properties object containing the calculated matrices: - reflectance, transmittance (Front interface) - reflectance_back, transmittance_back (Back interface) - wavelength, incidence_angle vectors.
- Return type:
- class iactsim.optics.GenericFlatModule(pixels, half_aperture, aperture_shape=ApertureShape.SQUARE, central_hole_half_aperture=0.0, central_hole_shape=ApertureShape.SQUARE, position=np.array([0., 0., 0.]), tilt_angles=np.array([0., 0., 0.]), scattering_dispersion=0.0, surface_type=SurfaceType.SENSITIVE, properties=None, material_in=Materials.AIR, material_out=Materials.AIR, name=None)
Represents a generic flat module with arbitrarily placed pixels.
- Parameters:
pixels (List[GenericPixel]) – List of GenericPixel objects defining the layout and properties of the module pixels.
half_aperture (float) – Outer dimension (radius, inradius, or half-side) of the entire module surface (must contain all pixels).
aperture_shape (ApertureShape, optional) – The shape of the module outer aperture, by default ApertureShape.SQUARE.
central_hole_half_aperture (float, optional) – Inner dimension (hole) of the module surface, by default 0.0.
central_hole_shape (ApertureShape, optional) – The shape of the central hole, by default ApertureShape.SQUARE.
position (array-like, optional) – Position of the surface center [x, y, z], by default None
tilt_angles (array-like, optional) – Tilt angles (counter-clockwise x-tilt, y-tilt and z_tilt) in degrees, by default no tilt.
scattering_dispersion (float, optional) – Standard deviation of Gaussian scattering after reflection/transmission, by default 0.0
surface_type (SurfaceType, optional) – Type of the sensitive surface, by default SurfaceType.SENSITIVE
properties (SurfaceProperties, optional) – Reflectance/transmittance properties of the unsensitive surface where pixels lie, by default None.
material_in (material, optional) – Material of the space before the surface front side, i.e. the material in which photons arriving with a negative z-component of their direction vector are travelling. By default standard air.
material_out (material, optional) – Material of the space after the surface back side. I.e. the material in which photons arriving with a positive z-component of their direction vector are travelling, by default standard air.
name (str, optional) – Surface name
Methods:
__repr__()Returns a string representation of the surface object.
__str__()Returns a string representation of the surface object formatted as a table.
Checks if all pixels are fully contained within the module outer aperture and fall completely outside the central hole (if any).
Returns the surface properties packed into a structured NumPy record.
Calculates the 3D rotation matrix to transform into the surface reference system from the telescope reference system.
Returns the sensor info array for the ray tracing kernel.
Calculate the upward-going normal unit vector at a given surface point (x,y) in the surface reference frame.
sagitta(r)Calculate the sagitta of the aspheric surface at a given radial distance in the surface refrence frame.
set_rotation_matrix(a_matrix)Set a custom rotation matrix instead of deriving it from tilt angles.
Attributes:
Treat the surface as a segment centered at these aperture coordinates.
- __str__()
Returns a string representation of the surface object formatted as a table.
- Return type:
- check_pixels_contained()
Checks if all pixels are fully contained within the module outer aperture and fall completely outside the central hole (if any).
This uses a conservative geometric check based on the bounding circle of each pixel.
- Returns:
True if all pixels are validly placed, False otherwise.
- Return type:
- get_cuda_record()
Returns the surface properties packed into a structured NumPy record.
- Return type:
- get_rotation_matrix()
Calculates the 3D rotation matrix to transform into the surface reference system from the telescope reference system.
The computation is based on surface tilt angles and assumes rotations are applied in the order (last first) Z @ Y @ X. This corresponds to rotating the surface around the telescope X axis, then the telescope Y axis and finally the telescope Z axis. The rotations follow the right-hand rule (counter-clockwise).
These angles are intended for small misalignments, while
create_surface_rotation()is a more robust method. Tilt angles can be bypassed if a custom rotation matrix has been set usingset_rotation_matrix()method.Tilt angles are expected in degrees.
- Return type:
- Returns:
np.ndarray: A 3x3 rotation matrix. The returned matrix is the transpose of the tilt sequence. It transforms from the telescope reference system into the surface reference system.
- get_sensor_info()
Returns the sensor info array for the ray tracing kernel. Automatically allocates and populates the PixelData and SurfaceOpticalTables arrays on the GPU.
- Returns:
An array of shape (8,) and dtype float32 containing the packed sensor data.
- Return type:
- get_surface_normal_vector(x, y)
Calculate the upward-going normal unit vector at a given surface point (x,y) in the surface reference frame.
- offset
Treat the surface as a segment centered at these aperture coordinates.
- sagitta(r)
Calculate the sagitta of the aspheric surface at a given radial distance in the surface refrence frame.
- Parameters:
r (np.ndarray, list or scalar) – Radial distance(s) from the optical axis.
- Returns:
Sagitta value(s) at the given radial distance(s).
- Return type:
np.ndarray
- set_rotation_matrix(a_matrix)
Set a custom rotation matrix instead of deriving it from tilt angles. To use tilt angles set it to
None.- Parameters:
a_matrix (np.ndarray) – 3D rotation matrix to transform from telescope to surface reference frame.
- class iactsim.optics.GenericPixel(x, y, half_size, shape, pixel_id, n_ucells_per_side=1, properties=None)
Represents a single pixel to be placed in a GenericFlatModule.
- half_size
Half-size of the pixel (inradius, radius or half-side, depending on the shape).
- Type:
- shape
Shape of the pixel aperture.
- Type:
- properties
Reflectance and/or efficiency of the pixel, by default None.
- Type:
SurfaceProperties, optional
Warning
Micro-cell ID calculation do not take into account the shape of the pixel. Instead, if the pixel is not square, the ID is calculated relative to a square with half-side equal to the circumradius of the pixel. The effect of this approximation has not been tested.
Methods:
Packs the pixel geometry into a structured NumPy array for CUDA kernels.
- class iactsim.optics.Materials
A collection of Material instances with refractive index data (wavelength in nm). Includes default materials: Air (Ciddor 1996) and Fused Silica (Malitson 1965).
New materials can be added using the
register_material()method:You can also replace a material, for example the air refractive index:
To register a refractive index for air, a
set_atmospheric_conditions()method is provided. It uses the Ciddor equation following the NIST implementation:Warning
Material integer IDs (
.value) are assigned sequentially starting from 0, strictly based on the order in which they are registered. Because there is no mechanism to unregister a material, the sequence is guaranteed to be gapless. Overwriting an existing material (overwrite=True) safely preserves its original integer ID. This gapless sequenceMethods:
set_atmospheric_conditions([pressure, ...])Calculate the refractive index of moist air using the Ciddor equation and update the default air material.
- classmethod set_atmospheric_conditions(pressure=101325., temperature=20., co2_concentration=450., relative_humidity=0., lambda_min=200., lambda_max=1700.)
Calculate the refractive index of moist air using the Ciddor equation and update the default air material.
Follows the NIST implementation described by Jack A. Stone and Jay H. Zimmerman.
- Parameters:
pressure (float) – Air pressure in Pascals.
temperature (float) – Air temperature in degrees Celsius.
co2_concentration (float) – CO2 concentration in micromoles per mole (µmol/mol), equivalent to ppm.
relative_humidity (Optional[float]) – Relative humidity in percent (%). If None, assumes dry air (xv = 0).
lambda_min (float, Optional[float]) – Minimum photon wavelength (in nm).
lambda_max (float, Optional[float]) – Maximum photon wavelength (in nm).
- Return type:
Notes
NIST implementation is valid in the range 300 nm - 1700 nm.
- class iactsim.optics.OpticalStackSimulator(core_materials, core_thicknesses, ambient='Air', substrate='SiO2', coh_list=[])
A class to handle dispersive Transfer Matrix Method (TMM) simulations using the tmm_fast backend, with a dynamic material database.
- Parameters:
core_materials (List[str]) – List of material names for the core layers (from top to bottom).
core_thicknesses (List[float]) – List of thicknesses for the core layers in nanometers.
ambient (str, optional) – Name of the ambient medium (default is “Air”).
substrate (str, optional) – Name of the substrate material (default is “SiO2”).
coh_mask (list, optional) – List of coherence tags (‘c’ for coherent, ‘i’ for incoherent) for each layer (including ambient and substrate). If empty, coherent simulation is assumed.
- Raises:
ImportError – If neither ‘tmm_fast’ nor ‘tmm’ package is installed.
Methods:
Returns a sorted list of all currently registered material names.
get_refractive_index(material, wavelengths_nm)Get the refractive index of a registered material at specified wavelengths.
plot_simulation_results([mode, cmap, ...])Plots simulation results for s-polarization, p-polarization, and unpolarized light.
register_ciddor_air([name, p, t, xCO2, rh])Register the air refractive index using the Ciddor equation.
register_material(name, n_func)Register a custom material using a refractive index function.
register_sellmeier_material(name, B_coeffs, ...)Register a material defined by the Sellmeier equation.
run([polarization])Run the TMM simulation for a specific polarization.
set_simulation_params([wl_range, angle_range])Set the wavelength (in nanometers) and angle ranges (in degrees).
- get_available_materials()
Returns a sorted list of all currently registered material names.
- get_refractive_index(material, wavelengths_nm)
Get the refractive index of a registered material at specified wavelengths.
- plot_simulation_results(mode='R', cmap='Spectral', show_all_pol=True)
Plots simulation results for s-polarization, p-polarization, and unpolarized light. Automatically calculates axis extent from the stored simulation parameters.
- register_ciddor_air(name='Air', p=101325.0, t=288.15, xCO2=450.0, rh=0.0)
Register the air refractive index using the Ciddor equation.
- Parameters:
name (str) – The material name to register (defaults to “Air”, overwriting the default vacuum).
p (float) – Pressure in Pascals (default 101325 Pa).
t (float) – Temperature in Kelvin (default 288.15 K).
xCO2 (float) – CO2 concentration in ppm (default 450 ppm).
rh (float, optional) – Relative humidity (0.0 to 1.0).
- Return type:
- register_material(name, n_func)
Register a custom material using a refractive index function.
- register_sellmeier_material(name, B_coeffs, C_coeffs)
Register a material defined by the Sellmeier equation.
- Return type:
- set_simulation_params(wl_range=(200, 1000, 801), angle_range=(0, 90, 91))
Set the wavelength (in nanometers) and angle ranges (in degrees).
- Parameters:
wl_range (Tuple, List, or np.ndarray) – If tuple: (start_nm, stop_nm, points). If array/list: exact wavelengths in Nanometers. Default is (200, 1000, 801).
angle_range (Tuple, List, or np.ndarray) – If tuple: (start_deg, stop_deg, points). If array/list: exact angles in Degrees. Default is (0, 90, 91).
- Return type:
- class iactsim.optics.OpticalSystem(surfaces, name=None)
Represents a generic optical system.
- Parameters:
name (str, optional) – Name of the optical system, by defaults “OS”.
surfaces (List[Surface]) – List of Surface objects representing the optical surfaces in the system (the order is not important).
Notes
Each surface has a name attribute that is used for named access. If a surface name is None, a default name “Surface_i” (where i is its index) is assigned.
Methods:
__getitem__(key)Allows accessing individual surfaces using indexing or by surface name.
__iter__()Returns an iterator over the optical surfaces.
__len__()Returns the number of optical surfaces in the system.
__repr__()Returns a string representation of the optical system.
add_surface(surface[, replace])Add a surface to the optical syste.
remove_surface(surface)Remove a given surface.
Attributes:
Provides a dictionary view of the surfaces, mapping names to
Surfaceobjects.- __getitem__(key)
Allows accessing individual surfaces using indexing or by surface name.
- Parameters:
- Returns:
The optical surface with the specified name or at the specified index.
- Return type:
OpticalSurface
- Raises:
KeyError – If a surface with the given name is not found.
IndexError – If the index is out of range.
TypeError – If the key is neither a string nor an integer.
- __iter__()
Returns an iterator over the optical surfaces.
- Returns:
An iterator object that iterates through the surfaces in self._surfaces.
- Return type:
iterator
- __len__()
Returns the number of optical surfaces in the system.
- Returns:
The number of surfaces.
- Return type:
- add_surface(surface, replace=False)
Add a surface to the optical syste.
- Parameters:
surface (Surface) – Surface to be added.
replace (bool, optional) – Whether to replace an exisisting surface with the same name, by default False.
- Raises:
ValueError – If the surface already exists and replace is False.
- remove_surface(surface)
Remove a given surface.
- Parameters:
surface (Surface or str) – Surface instance or name to be removed.
- property surfaces_dict: Dict[str, AsphericalSurface]
Provides a dictionary view of the surfaces, mapping names to
Surfaceobjects.
- class iactsim.optics.RefractiveIndexTexture(texture, wavelength_start, wavelength_inv_step, _cuda_array=None)
Holds the texture object and metadata for refractive index lookups. It retains a reference to the underlying CUDA array to prevent premature garbage collection.
- class iactsim.optics.SensorSurfaceType(*values)
Enumeration representing different types of sensor surfaces.
Methods:
__contains__(value)Return True if value is in cls.
__getitem__(name)Return the member matching name.
__iter__()Return members in definition order.
__len__()Return the number of members (no aliases)
- classmethod __contains__(value)
Return True if value is in cls.
value is in cls if: 1) value is a member of cls, or 2) value is the value of one of the cls’s members.
- classmethod __getitem__(name)
Return the member matching name.
- classmethod __iter__()
Return members in definition order.
- classmethod __len__()
Return the number of members (no aliases)
- class iactsim.optics.SipmStackSimulator(layers, thicknesses, medium, type_layers, depletion_layer_depth=5.0, depletion_layer_width=2100.0, fill_factor=1.0, breakdown_probability=1.0, ucell_size=75e-6)
A simulator for calculating the Photon Detection Efficiency (PDE) of Silicon Photomultipliers (SiPMs) given a coating stack.
This class extends OpticalStackSimulator to model the optical transport through thin-film coatings into a Silicon substrate. It calculates the PDE by combining optical transmittance with the probability of electron-hole pair generation within the active depletion region.
- Parameters:
layers (list of str) – List of material names for the coating stack (e.g.,
["Si3N4", "SiO2"]).thicknesses (list of float) – List of layer thicknesses in meters.
medium (str) – The incident medium material name (e.g.,
"Air").type_layers (list of str) – List of layer types corresponding to layers: -
'c': Coherent (phase-sensitive, interference calculated). -'i': Incoherent (phase-averaged, intensity addition).depletion_layer_depth (float, optional) – Depth of the start of the depletion region ($x_1$) in nm. Default is 5.0 nm.
depletion_layer_width (float, optional) – Depth extent of the depletion region ($x_2$) in nm. Default is 2100.0 nm.
fill_factor (float, optional) – Geometric fill factor ($FF$). Default is 1.0.
breakdown_probability (float, optional) – Avalanche triggering probability ($P_{br}$). Default is 1.0.
ucell_size (float, optional) – Size of the micro-cell in meters. Default is 75e-6 m.
Methods:
constrain_pde(lambda0, pde0)Adjusts the breakdown probability to force the PDE to match a specific value at a specific wavelength (at normal incidence).
Returns a sorted list of all currently registered material names.
get_refractive_index(material, wavelengths_nm)Get the refractive index of a registered material at specified wavelengths.
get_surfcace_properties_obj([...])Creates a SurfaceProperties object from the simulation results.
plot_pde_normal([compare_data, compare_model])Plots the simulated PDE at normal incidence against optional comparison data.
plot_pde_results([mode, cmap])Plots simulation results for s-polarization, p-polarization, and unpolarized light.
plot_simulation_results([mode, cmap, ...])Plots simulation results for s-polarization, p-polarization, and unpolarized light.
register_ciddor_air([name, p, t, xCO2, rh])Register the air refractive index using the Ciddor equation.
register_material(name, n_func)Register a custom material using a refractive index function.
register_sellmeier_material(name, B_coeffs, ...)Register a material defined by the Sellmeier equation.
run([polarization])Execute the simulation to calculate quantum efficiency and PDE.
set_simulation_params([wl_range, angle_range])Set the wavelength (in nanometers) and angle ranges (in degrees).
- constrain_pde(lambda0, pde0)
Adjusts the breakdown probability to force the PDE to match a specific value at a specific wavelength (at normal incidence).
This is useful for calibrating the model against a known experimental data point. It modifies
self.breakdown_probabilityin place.- Parameters:
- Raises:
RuntimeError – If
run()has not been called yet.
- get_available_materials()
Returns a sorted list of all currently registered material names.
- get_refractive_index(material, wavelengths_nm)
Get the refractive index of a registered material at specified wavelengths.
- get_surfcace_properties_obj(with_reflections=True, side='both')
Creates a SurfaceProperties object from the simulation results.
- Parameters:
with_reflections (bool, optional) – If True, the surface properties will include the simulated reflectance and absorption. The detection efficiency will be defined relative to absorbed photons (‘absorbed’ kind). If False, reflectance is set to zero, and detection efficiency is defined relative to incident photons (‘incident’ kind). Default is True.
side (str, optional) – Specifies which side(s) of the surface to populate properties for. Options are ‘front’, ‘back’, or ‘both’. Default is ‘both’.
- Returns:
The populated surface properties object containing wavelength, incidence angle, reflectance, absorption, and efficiency data.
- Return type:
- plot_pde_normal(compare_data=None, compare_model=None)
Plots the simulated PDE at normal incidence against optional comparison data.
- plot_pde_results(mode='R', cmap='Spectral')
Plots simulation results for s-polarization, p-polarization, and unpolarized light. Automatically calculates axis extent from the stored simulation parameters.
- plot_simulation_results(mode='R', cmap='Spectral', show_all_pol=True)
Plots simulation results for s-polarization, p-polarization, and unpolarized light. Automatically calculates axis extent from the stored simulation parameters.
- register_ciddor_air(name='Air', p=101325.0, t=288.15, xCO2=450.0, rh=0.0)
Register the air refractive index using the Ciddor equation.
- Parameters:
name (str) – The material name to register (defaults to “Air”, overwriting the default vacuum).
p (float) – Pressure in Pascals (default 101325 Pa).
t (float) – Temperature in Kelvin (default 288.15 K).
xCO2 (float) – CO2 concentration in ppm (default 450 ppm).
rh (float, optional) – Relative humidity (0.0 to 1.0).
- Return type:
- register_material(name, n_func)
Register a custom material using a refractive index function.
- register_sellmeier_material(name, B_coeffs, C_coeffs)
Register a material defined by the Sellmeier equation.
- Return type:
- run(polarization='unpolarized')
Execute the simulation to calculate quantum efficiency and PDE.
The method performs the following steps: 1. Calculate optical transmittance into the Silicon substrate. 2. Calculate the internal path lengths correcting for refraction/incidence angle. 3. Computes the Silicon absorption coefficient from the complex refractive index. 4. Computes the probability of photon absorption strictly within the depletion region. 5. Combines factors: $PDE = T times P_{int} times FF times P_{br}$.
- Parameters:
polarization (str, optional) – Polarization mode:
's','p', or'unpolarized'(default). If'unpolarized', the average of s and p transmittances is used.- Returns:
The calculated PDE array with shape (n_angles, n_wavelengths).
- Return type:
np.ndarray
- set_simulation_params(wl_range=(200, 1000, 801), angle_range=(0, 90, 91))
Set the wavelength (in nanometers) and angle ranges (in degrees).
- Parameters:
wl_range (Tuple, List, or np.ndarray) – If tuple: (start_nm, stop_nm, points). If array/list: exact wavelengths in Nanometers. Default is (200, 1000, 801).
angle_range (Tuple, List, or np.ndarray) – If tuple: (start_deg, stop_deg, points). If array/list: exact angles in Degrees. Default is (0, 90, 91).
- Return type:
- class iactsim.optics.SipmTileSurface(pixels_per_side, pixel_active_side, pixels_separation, border_to_active_area, sensor_id, first_pixel_id, microcell_size=0.0, position=np.array([0., 0., 0.]), tilt_angles=np.array([0., 0., 0.]), scattering_dispersion=0.0, surface_type=SurfaceType.SENSITIVE, properties=None, material_in=Materials.AIR, material_out=Materials.AIR, name=None)
Represents a SiPM tile of NxN pixels.
- Parameters:
pixels_per_side (int) – Number of pixels per side.
pixel_active_side (float) – Side length of the active area of a single pixel.
pixels_separation (float) – Separation between pixels.
border_to_active_area (float) – Width of the border from the edge of the tile to the active area.
sensor_id (int) – Unique identifier for the sensor.
first_pixel_id (int) – ID of the first pixel in the tile.
microcell_size (float, optional) – Size of a pixel micro-cell in mm (e.g. 0.075 for 75um ucells), by default 0.0 (i.e. not considered).
position (array-like, optional) – Position of the surface center [x, y, z], by default None
tilt_angles (array-like, optional) – Tilt angles (counter-clockwise x-tilt, y-tilt and z_tilt) in degrees, by default no tilt.
scattering_dispersion (float, optional) – Standard deviation of Gaussian scattering after reflection/transmission, by default 0.0
properties (SurfaceProperties, optional) – Reflectance/transmittance properties of the surface, by default None
material_in (material, optional) – Material of the space before the surface front side. I.e. the material in which photons arriving with a negative z-component of their direction vector are travelling, by default standard air.
material_out (material, optional) – Material of the space after the surface back side. I.e. the material in which photons arriving with a positive z-component of their direction vector are travelling, by default standard air.
name (str, optional) – Surface name
Notes
Tile layout:
y pixels_separation ^ ________ <--> ________ | | | | | | | | | | | | | | | | |________| |________| |<-> <------> | | pixel_active_side | border_to_active_area (0,0)---------> x
Methods:
__repr__()Returns a string representation of the surface object.
__str__()Returns a string representation of the surface object formatted as a table.
Returns the surface properties packed into a structured NumPy record.
Calculates the 3D rotation matrix to transform into the surface reference system from the telescope reference system.
Calculate the upward-going normal unit vector at a given surface point (x,y) in the surface reference frame.
sagitta(r)Calculate the sagitta of the aspheric surface at a given radial distance in the surface refrence frame.
set_rotation_matrix(a_matrix)Set a custom rotation matrix instead of deriving it from tilt angles.
Attributes:
Treat the surface as a segment centered at these aperture coordinates.
- __str__()
Returns a string representation of the surface object formatted as a table.
- Return type:
- get_cuda_record()
Returns the surface properties packed into a structured NumPy record.
- Return type:
- get_rotation_matrix()
Calculates the 3D rotation matrix to transform into the surface reference system from the telescope reference system.
The computation is based on surface tilt angles and assumes rotations are applied in the order (last first) Z @ Y @ X. This corresponds to rotating the surface around the telescope X axis, then the telescope Y axis and finally the telescope Z axis. The rotations follow the right-hand rule (counter-clockwise).
These angles are intended for small misalignments, while
create_surface_rotation()is a more robust method. Tilt angles can be bypassed if a custom rotation matrix has been set usingset_rotation_matrix()method.Tilt angles are expected in degrees.
- Return type:
- Returns:
np.ndarray: A 3x3 rotation matrix. The returned matrix is the transpose of the tilt sequence. It transforms from the telescope reference system into the surface reference system.
- get_surface_normal_vector(x, y)
Calculate the upward-going normal unit vector at a given surface point (x,y) in the surface reference frame.
- offset
Treat the surface as a segment centered at these aperture coordinates.
- sagitta(r)
Calculate the sagitta of the aspheric surface at a given radial distance in the surface refrence frame.
- Parameters:
r (np.ndarray, list or scalar) – Radial distance(s) from the optical axis.
- Returns:
Sagitta value(s) at the given radial distance(s).
- Return type:
np.ndarray
- set_rotation_matrix(a_matrix)
Set a custom rotation matrix instead of deriving it from tilt angles. To use tilt angles set it to
None.- Parameters:
a_matrix (np.ndarray) – 3D rotation matrix to transform from telescope to surface reference frame.
- class iactsim.optics.SphericalSurface(half_aperture, curvature, central_hole_half_aperture=0., aperture_shape=ApertureShape.CIRCULAR, central_hole_shape=ApertureShape.CIRCULAR, is_fresnel=False, surface_type=SurfaceType.REFLECTIVE, position=np.array([0., 0., 0.]), tilt_angles=np.array([0., 0., 0.]), scattering_dispersion=0., properties=None, material_in=Materials.AIR, material_out=Materials.AIR, name=None)
Represents a spherical optical surface.
- Parameters:
half_aperture (float) – Half-aperture of the surface.
curvature (float) – Surface curvature (1/radius of curvature)
central_hole_half_aperture (float, optional) – Half-aperture of the central hole (0.0 if no hole), by default 0.0
aperture_shape (ApertureShape, optional) – Shape of the aperture (circular, hexagonal or rectangular), by default ApertureShape.CIRCULAR
central_hole_shape (ApertureShape, optional) – Shape of the central hole (circular, hexagonal or rectangular), by default ApertureShape.CIRCULAR
is_fresnel (bool, optional) – Whether the surface is an ideal Fresnel lens/mirror, by default False
surface_type (SurfaceType, optional) – Type of surface (reflective, refractive, opaque, dummy), by default SurfaceType.REFLECTIVE
position (array-like, optional) – Position of the surface center [x, y, z], by default None
tilt_angles (array-like, optional) – Tilt angles (counter-clockwise x-tilt, y-tilt and z_tilt) in degrees, by default no tilt.
scattering_dispersion (float, optional) – Standard deviation of Gaussian scattering after reflection/transmission, by default 0.
properties (SurfaceProperties, optional) – Reflectance/transmittance properties of the surface, by default None
material_in (material, optional) – Material of the space before the surface front side. I.e. the material in which photons arriving with a negative z-component of their direction vector are travelling, by default standard air.
material_out (material, optional) – Material of the space after the surface back side. I.e. the material in which photons arriving with a positive z-component of their direction vector are travelling, by default standard air.
name (str, optional) – Surface name
Methods:
__repr__()Returns a string representation of the surface object.
__str__()Returns a string representation of the surface object formatted as a table.
Returns the surface properties packed into a structured NumPy record.
Calculates the 3D rotation matrix to transform into the surface reference system from the telescope reference system.
Calculate the upward-going normal unit vector at a given surface point (x,y) in the surface reference frame.
sagitta(r)Calculate the sagitta of the aspheric surface at a given radial distance in the surface refrence frame.
set_rotation_matrix(a_matrix)Set a custom rotation matrix instead of deriving it from tilt angles.
Attributes:
Treat the surface as a segment centered at these aperture coordinates.
- __str__()
Returns a string representation of the surface object formatted as a table.
- Return type:
- get_cuda_record()
Returns the surface properties packed into a structured NumPy record.
- Return type:
- get_rotation_matrix()
Calculates the 3D rotation matrix to transform into the surface reference system from the telescope reference system.
The computation is based on surface tilt angles and assumes rotations are applied in the order (last first) Z @ Y @ X. This corresponds to rotating the surface around the telescope X axis, then the telescope Y axis and finally the telescope Z axis. The rotations follow the right-hand rule (counter-clockwise).
These angles are intended for small misalignments, while
create_surface_rotation()is a more robust method. Tilt angles can be bypassed if a custom rotation matrix has been set usingset_rotation_matrix()method.Tilt angles are expected in degrees.
- Return type:
- Returns:
np.ndarray: A 3x3 rotation matrix. The returned matrix is the transpose of the tilt sequence. It transforms from the telescope reference system into the surface reference system.
- get_surface_normal_vector(x, y)
Calculate the upward-going normal unit vector at a given surface point (x,y) in the surface reference frame.
- offset
Treat the surface as a segment centered at these aperture coordinates.
- sagitta(r)
Calculate the sagitta of the aspheric surface at a given radial distance in the surface refrence frame.
- Parameters:
r (np.ndarray, list or scalar) – Radial distance(s) from the optical axis.
- Returns:
Sagitta value(s) at the given radial distance(s).
- Return type:
np.ndarray
- set_rotation_matrix(a_matrix)
Set a custom rotation matrix instead of deriving it from tilt angles. To use tilt angles set it to
None.- Parameters:
a_matrix (np.ndarray) – 3D rotation matrix to transform from telescope to surface reference frame.
- class iactsim.optics.SurfaceProperties(transmittance=None, reflectance=None, absorption=None, transmittance_back=None, reflectance_back=None, absorption_back=None, wavelength=None, incidence_angle=None, efficiency=None, efficiency_kind='incident', efficiency_wavelength=None, efficiency_incidence_angle=None)
Represents surface transmittance, reflectance, absorption and detection efficiency as a function of photon wavelength and incidence angle.
Attributes:
'incident' (relative to incoming photons) or 'absorbed' (relative to absorbed photons).
Methods:
Packs the texture pointers and grid metadata into a structured NumPy array for CUDA kernels.
Creates and caches a SurfaceTextures object.
load_json(filename)Loads surface attributes from a JSON file.
plot([kind, heatmap, cmap, level_range])Plot properties including transmittance, reflectance, absorption, and efficiency.
save_json(filename)Saves the raw surface attributes to a JSON file.
-
efficiency_kind:
str= 'incident' ‘incident’ (relative to incoming photons) or ‘absorbed’ (relative to absorbed photons).
- get_cuda_record()
Packs the texture pointers and grid metadata into a structured NumPy array for CUDA kernels.
- Return type:
- get_textures()
Creates and caches a SurfaceTextures object. If properties haven’t changed, returns the cached version.
- Return type:
- classmethod load_json(filename)
Loads surface attributes from a JSON file.
- plot(kind='transmittance', heatmap=None, cmap='Spectral', level_range=(None, None))
Plot properties including transmittance, reflectance, absorption, and efficiency.
- save_json(filename)
Saves the raw surface attributes to a JSON file.
-
efficiency_kind:
- class iactsim.optics.SurfaceShape(*values)
Enumeration representing different types of surface shapes.
This enum defines common surface shapes encountered in optical systems or other fields requiring precise geometrical definitions.
Attributes:
Represents an aspherical surface.
Represents a box-like surface.
Represents a conical surface.
Represents a cylindrical surface.
Represents a flat surface.
Represents a spherical surface.
Methods:
__contains__(value)Return True if value is in cls.
__getitem__(name)Return the member matching name.
__iter__()Return members in definition order.
__len__()Return the number of members (no aliases)
- ASPHERICAL = 0
Represents an aspherical surface.
- BOX = 5
Represents a box-like surface.
- CONICAL = 4
Represents a conical surface.
- CYLINDRICAL = 1
Represents a cylindrical surface.
- FLAT = 2
Represents a flat surface.
- SPHERICAL = 3
Represents a spherical surface.
- classmethod __contains__(value)
Return True if value is in cls.
value is in cls if: 1) value is a member of cls, or 2) value is the value of one of the cls’s members.
- classmethod __getitem__(name)
Return the member matching name.
- classmethod __iter__()
Return members in definition order.
- classmethod __len__()
Return the number of members (no aliases)
- class iactsim.optics.SurfaceTextures(transmittance, reflectance, transmittance_back, reflectance_back, optical_wavelength_start, optical_wavelength_inv_step, optical_angle_start, optical_angle_inv_step, efficiency, efficiency_wavelength_start, efficiency_wavelength_inv_step, efficiency_angle_start, efficiency_angle_inv_step, _t_array=None, _r_array=None, _t_back_array=None, _r_back_array=None, _eff_array=None)
Container for GPU texture objects (optical + efficiency) and the metadata required to map physical values (wavelength, angle) to texture coordinates. It can retains a reference to the underlying CUDA arrays to prevent premature garbage collection. Because efficiency can be defined on a different grid than transmittance/reflectance, this class stores two separate sets of coordinate mappings.
Methods:
Packs the texture pointers and grid metadata into a structured NumPy array for CUDA.
- class iactsim.optics.SurfaceType(*values)
Enumeration representing the different types of optical surfaces.
The directionality of reflection and sensitivity (e.g., “from above” or “from below”) is defined within the local reference frame of the surface at the point of photon incidence. As a reference:
the front side of a surface with negative curvature is the convex side.
the front side of a surface with posistive curvature is the concave side.
- REFLECTIVE_FRONT
Represents a surface that is reflective on the front side. In the surface reference frame, only photons arriving with a negative z-component of their direction vector are reflected. The curvature of the surface does not affect this behavior.
- Type:
- REFLECTIVE_BACK
Represents a surface that is reflective on the back side. In the surface reference frame, only photons arriving with a positive z-component of their direction vector are reflected. The curvature of the surface does not affect this behavior.
- Type:
- SENSITIVE
Represents the focal plane surface where photons are detected. The sensitivity is the same on both sides.
- Type:
- SENSITIVE_BACK
Represents a surface that is sensitive on the front side. In the surface reference frame, only photons arriving with a negative z-component of their direction vector are detected. The curvature of the surface does not affect this behavior.
- Type:
- SENSITIVE_FRONT
Represents a surface that is sensitive on the back side. In the surface reference frame, only photons arriving with a positive z-component of their direction vector are detected. The curvature of the surface does not affect this behavior.
- Type:
- DUMMY
Represents a surface that neither reflects nor refracts light. It can be used to introduce artificial absorption or scattering effects, serving as a means to model specific behaviors within the optical system.
- Type:
Methods:
__contains__(value)Return True if value is in cls.
__getitem__(name)Return the member matching name.
__iter__()Return members in definition order.
__len__()Return the number of members (no aliases)
- classmethod __contains__(value)
Return True if value is in cls.
value is in cls if: 1) value is a member of cls, or 2) value is the value of one of the cls’s members.
- classmethod __getitem__(name)
Return the member matching name.
- classmethod __iter__()
Return members in definition order.
- classmethod __len__()
Return the number of members (no aliases)
- class iactsim.optics.SurfaceVisualProperties(color=None, opacity=None, specular=None, wireframe=False, resolution=None, visible=True)
Stores visualization attributes for an optical surface.
- Parameters:
color (tuple of float, optional) – RGB color tuple (0.0-1.0). If None, the visualizer uses default logic based on surface type.
opacity (float, optional) – Opacity (0.0 transparent - 1.0 opaque). If None, visualizer uses default logic based on surface type.
specular (float, optional) – Specular reflection intensity (0.0-1.0).
wireframe (bool, optional) – If True, forces wireframe representation for this surface. Default is False.
resolution (float, optional) – Mesh resolution in mm. If None, uses the visualizer logic based on the surface extent.
visible (bool, optional) – Whether the surface is visible in the render. Default is True.
optics.ray_tracing
Functions:
Simulates atmospheric transmission. |
|
Generates wavelengths for bunches using the Cherenkov emission spectrum. |
|
The main ray tracing kernel. |
|
Applies rejection to photons based on their fractional weights. |
|
Shift bunches from the current plane (the telescope plane in the case of CORSIKA files) to a plane at a level target_z |
|
Unpacks photon bunches into individual photons and generates unique wavelengths following the Cherenkov emission spectrum. |
- iactsim.optics.ray_tracing.atmospheric_transmission()
Simulates atmospheric transmission.
This kernel function applies atmospheric transmission rejecting photons based on a 2D transmission curve (wavelength and emission altitude). Physically, it models the attenuation of light due to scattering (Rayleigh/Mie) and molecular absorption (like ozone) by evaluating the Beer-Lambert law.
- Parameters:
ps (float3*) – Array of photon positions.
vs (float3*) – Array of photon directions. The z-component scales the path length the photon takes through the atmosphere.
wls (float*) – Array of photon wavelengths.
ts (float*) – Array of photon times.
zems (const float*) – Array of photon emission altitudes.
tr_curves (const float*) – Array containing the 2D transmission curve data, i.e. a lookup table of vertical optical depths (tau).
tr_curve_wl (const float*) – Array of wavelength values for the transmission curve.
tr_curve_zem (const float*) – Array of emission altitude values for the transmission curve.
tr_curve_sizes (const int*) – Array containing the dimensions (x1_size, x2_size) of the 2D transmission curve.
tr_curve_sizes[0]is the wavelength size, andtr_curve_sizes[1]is the emission altitude size.n_ph (int) – The total number of photons.
seed (unsigned long long) – Random seed to initialize the RNG.
use_log_z (bool) – If true, the emission altitude interpolation uses logarithmic weighting.
Notes
Input array usage: - used to compute transmission:
wls,zems,vs,tr_curves,tr_curve_wl,tr_curve_zem, andtr_curve_sizes. - used only to reject photons:psandts(These, along withvsandwls, are passed to the rejection function to update photon state).Attention
This is a wrapped CuPy RawKernel object, you can launch it as follows:
blocks = ... # Number of blocks threads = ... # Number of threads per block shared_memory = ... # Dynamic shared memory buffer size (if needed) args = (...) # Provide the arguments kernel(grid, block, args, shared_mem=shared_memory)
If you are new to CuPy, please see the CuPy documentation.
- iactsim.optics.ray_tracing.generate_bunch_wavelengths()
Generates wavelengths for bunches using the Cherenkov emission spectrum.
- Parameters:
Attention
This is a wrapped CuPy RawKernel object, you can launch it as follows:
blocks = ... # Number of blocks threads = ... # Number of threads per block shared_memory = ... # Dynamic shared memory buffer size (if needed) args = (...) # Provide the arguments kernel(grid, block, args, shared_mem=shared_memory)
If you are new to CuPy, please see the CuPy documentation.
- iactsim.optics.ray_tracing.ray_tracing()
The main ray tracing kernel.
This kernel traces individual photons through an optical system, simulating their interactions with surfaces. Surface properties are consolidated into an array of SurfaceData structures.
Interpretation of SurfaceData members depends on surface type:
Aperture Size (SurfaceData.aperture_size):
For aspherical, spherical and flat surfaces: half-aperture of the surface (aperture_size.x) and half-aperture of the central hole (aperture_size.y). The interpretation depends on the outer and inner shape: the radius for “circular”, inradius for “hexagonal” and half-side for “square”.
For a cylindrical surface they represent radius (aperture_size.x) and height (aperture_size.y).
Flags (SurfaceData.flags):
For aspherical and spherical surfaces: flags[0] indicates if a surface is a Fresnel surface (i.e. is flat, but has the same normal of a non-flat surface).
For cylindrical surfaces: flags[0] indicates if the surface has a top flat surface; flags[1] indicates if the surface has a bottom flat surface. If both are true the surface is a solid cylinder.
- Parameters:
ps (float3*) – Array of photon positions (x, y, z).
vs (float3*) – Array of photon directions (normalized vectors, x, y, z).
wls (float*) – Array of photon wavelengths.
times (float*) – Array of photon times (time elapsed since the start of the trace).
pixel_ids (int*) – ID of the pixel reached by the photon.
sub_pixel_ids (int*) – ID of the sub-pixel reached by the photon.
surface_ids (int*) – ID of the surface (stores the surface ID if save_last_bounce is true, otherwise 0).
telescope_position (const float3*) – Position of the telescope (global system).
telescope_rotation_matrix (const float*) – Rotation matrix of the telescope (global system).
surfaces (const SurfaceData*) – Array of SurfaceData structures containing geometry and physical properties for each surface.
optical_tables (const SurfaceOpticalTables*) – Structure containing texture objects and scaling factors for surface transmittance/reflectance.
refractive_tables (const RefractiveIndexTable*) – Array of RefractiveIndexTable structures (one per material) for refractive index lookups.
num_surfaces (int) – The total number of surfaces in the optical system.
num_photons (int) – The total number of photons to trace.
max_bounces (int) – Maximum number of interactions allowed per photon.
save_last_bounce (bool) – If true, stores the position of the last bounce (updates surface_ids).
trans_det_back_to_telescope (bool) – Whether to move detected photons into the telescope reference system.
seed (unsigned long long) – Random number generator seed.
Attention
This is a wrapped CuPy RawKernel object, you can launch it as follows:
blocks = ... # Number of blocks threads = ... # Number of threads per block shared_memory = ... # Dynamic shared memory buffer size (if needed) args = (...) # Provide the arguments kernel(grid, block, args, shared_mem=shared_memory)
If you are new to CuPy, please see the CuPy documentation.
- iactsim.optics.ray_tracing.reject_by_weight()
Applies rejection to photons based on their fractional weights.
@param[in,out] ps Pointer to the array of photon positions @param[in,out] vs Pointer to the array of photon directions @param[in,out] wls Pointer to the array of photon wavelengths @param[in,out] ts Pointer to the array of photon arrival times @param[in] weights Pointer to the array of fractional weights [0., 1.] for each photon @param[in] n Total number of photons to process @param[in] seed Base random seed to initialize the cuRAND state
This kernel evaluates the survival probability of each photon given a fractional photon weight (between 0. and 1.). It generates a uniform random number for each thread; if the random number exceeds the photon weight, the photon is discarded using the reject_photon device function (which sets its position, direction, time, and wavelength to NaN).
Attention
This is a wrapped CuPy RawKernel object, you can launch it as follows:
blocks = ... # Number of blocks threads = ... # Number of threads per block shared_memory = ... # Dynamic shared memory buffer size (if needed) args = (...) # Provide the arguments kernel(grid, block, args, shared_mem=shared_memory)
If you are new to CuPy, please see the CuPy documentation.
- iactsim.optics.ray_tracing.shift_bunches_position()
Shift bunches from the current plane (the telescope plane in the case of CORSIKA files) to a plane at a level target_z
and update their time using the refractive index provided.
- Parameters:
ps (float3*) – Pointer to the array of bunch positions.
vs (float3*) – Pointer to the array of bunch directions.
times (float*) – Pointer to the array of bunch arrival times.
wls (const float*) – Pointer to the array of bunch wavelengths.
target_z (float) – The target Z distance.
air_ri_table (Unknown) – RefractiveIndexTable struct for air to calculate light speed.
n_bunches (int) – Total number of bunches.
Attention
This is a wrapped CuPy RawKernel object, you can launch it as follows:
blocks = ... # Number of blocks threads = ... # Number of threads per block shared_memory = ... # Dynamic shared memory buffer size (if needed) args = (...) # Provide the arguments kernel(grid, block, args, shared_mem=shared_memory)
If you are new to CuPy, please see the CuPy documentation.
- iactsim.optics.ray_tracing.unpack_bunches()
Unpacks photon bunches into individual photons and generates unique wavelengths following the Cherenkov emission spectrum.
@param[in] in_pos Pointer to the input array of bunch positions @param[in] in_dir Pointer to the input array of bunch directions @param[in] in_time Pointer to the input array of bunch arrival times @param[in] in_alt Pointer to the input array of bunch emission altitudes @param[in] in_weight Pointer to the input array of bunch weights @param[out] out_pos Pointer to the output array of unpacked photon positions @param[out] out_dir Pointer to the output array of unpacked photon directions @param[out] out_time Pointer to the output array of unpacked photon arrival times @param[out] out_alt Pointer to the output array of unpacked photon emission altitudes @param[out] out_wl Pointer to the output array of generated photon wavelengths @param[out] out_weight Pointer to the output array of unpacked photon weights @param[in] bunch_size The number of individual photons contained in each single bunch @param[in] inv_l_min Inverse of the minimum wavelength boundary @param[in] inv_l_max Inverse of the maximum wavelength boundary @param[in] N_out Total number of output photons (number of input bunches times bunch size) @param[in] has_alt Boolean flag indicating whether emission altitudes should be copied @param[in] has_weight Boolean flag indicating whether fractional weights should be distributed @param[in] seed Random seed
This CUDA kernel expands arrays of photon “bunches” into individual photons. If a bunch contains bunch_size photons, its physical properties (position, direction, time, and optionally emission altitude) are duplicated bunch_size times in the output arrays. Simultaneously, a unique wavelength is assigned to each unpacked photon by sampling the Cherenkov emission spectrum, in the provided range, using a pre-generated uniformly distributed random number. If has_weight is true, the original bunch fractional weight is distributed across its unpacked constituent photons. For a bunch size of $N$ and a weight $W$ (where $W le N$), the first $lfloor W rfloor$ photons are assigned a weight of 1. The next photon receives the fractional remainder ($W - lfloor W rfloor$). Any subsequent photons in the bunch receive a weight of 0.
Attention
This is a wrapped CuPy RawKernel object, you can launch it as follows:
blocks = ... # Number of blocks threads = ... # Number of threads per block shared_memory = ... # Dynamic shared memory buffer size (if needed) args = (...) # Provide the arguments kernel(grid, block, args, shared_mem=shared_memory)
If you are new to CuPy, please see the CuPy documentation.
optics.transforms
Functions:
|
Computes a rotation matrix to transform from the telescope reference frame to the surface reference frame. |
Compute the rotation matrix to transform vector u to the local vertical Z-axis (0,0,1). |
|
|
Compute the rotation matrix to transform from the local reference frame (North-West-Up) to the "pointing reference frame". |
|
Compute the rotation matrix to transform from the local reference frame (North-West-Up) to the "telescope reference frame". |
Transforms photon positions and directions based on a telescope position and orientation. |
|
|
Telescope pointing direction in the corsika-like local reference frame. |
- iactsim.optics.transforms.create_surface_rotation(normal, up=np.array([1, 0, 0]))
Computes a rotation matrix to transform from the telescope reference frame to the surface reference frame.
In the surface reference system:
the Z-axis (0, 0, 1) is aligned with the input
normal;the Y-axis (0, 1, 0) is aligned as close as possible to the input
upvector;the X-axis (1, 0, 0) is mutually orthogonal.
- Parameters:
normal (np.ndarray) – The vector in the telescope reference system that defines where the surface is facing. This will become the surface Z-axis.
up (np.ndarray, optional) – The vector in the telescope reference system that defines the “top” of the surface. The surface Y-axis will be constructed by projecting this vector onto the plane perpendicular to the normal. Defaults to the X axis of telescope reference frame ([1, 0, 0]).
- Returns:
R – The 3x3 rotation matrix.
Usage:
v_surf = R @ v_telescopeifv_telescopehas shape (3,)v_surf = v_telescope @ R.Tifv_telescopehas shape (N,3)
- Return type:
ndarray, shape (3, 3)
Notes
The ID of each pixel of a SiPM tile is defined in the tile reference system as follows:
^ y | _____ _____ _____ | | | | | | | | | 6 | | 7 | | 8 | | |_____| |_____| |_____| | _____ _____ _____ | | | | | | | | | 3 | | 4 | | 5 | | |_____| |_____| |_____| | _____ _____ _____ | | | | | | | | | 0 | | 1 | | 2 | | |_____| |_____| |_____| | ------------------------------> x
So, the SiPM tile rotation matrix must be carefully set to match the desired ID convention.
Examples
# Opposite to the pointing direction sensor_normal = np.array([0., 0., -1.]) # Align the surface y axis with the telescope y axis R = create_surface_rotation(normal=sensor_normal, up=np.array([0., 1., 0.]))
- iactsim.optics.transforms.local_to_photon_rotation(u)
Compute the rotation matrix to transform vector u to the local vertical Z-axis (0,0,1).
This uses the Rodrigues rotation formula.
- Parameters:
u (ndarray, shape (3,)) – The source unit vector (e.g., photon direction).
- Returns:
R – Rotation matrix such that R @ u = [0, 0, 1].
- Return type:
ndarray, shape (3, 3)
- iactsim.optics.transforms.local_to_pointing_rotation(altitude, azimuth)
Compute the rotation matrix to transform from the local reference frame (North-West-Up) to the “pointing reference frame”.
This reference frame is defined such that when the telescope is pointing at the horizon towards the North (i.e. alt: 0, az: 0), the axes are aligned as follows:
z-axis: aligned with the telescope optical axis, pointing North.
x-axis: perpendicular to the optical axis, pointing downward.
y-axis: perpendicular to the optical axis, pointing west.
- Parameters:
- Returns:
R – Rotation matrix. When a vector in the local reference frame is multiplied by this matrix it is transformed into the telescope reference frame.
- Return type:
ndarray, shape (3, 3)
Notes
This is a simple rotation of the CORSIKA reference frame that move the up-vector (z) into the telescope direction.
- iactsim.optics.transforms.local_to_telescope_rotation(altitude, azimuth, custom_rotation=None)
Compute the rotation matrix to transform from the local reference frame (North-West-Up) to the “telescope reference frame”. By deault the telescope refrence frame is the pointing reference frame (see
local_to_pointing_rotation()).- Parameters:
- Returns:
R – Rotation matrix. When a vector in the local reference frame is multiplied by this matrix it is transformed into the telescope reference frame.
- Return type:
ndarray, shape (3, 3)
Examples
To rotate the telescope frame around the optical axis (Z-axis), while keeping Z pointing in the same direction:
import numpy as np # Rotation around Z-axis rotation = np.array([ [ 0, 1, 0], # new X is old Y [ 1, 0, 0], # new Y is old X [ 0, 0, 1] ]) # Get the telescope transformation matrix R_tel = local_to_telescope_rotation( altitude=70, azimuth=180, custom_rotation=rotation )
Now when the telescope is pointing North:
z-axis: aligned with the telescope optical axis, pointing North;
y-axis: perpendicular to the optical axis, pointing downward;
x-axis: perpendicular to the optical axis, pointing west.
- iactsim.optics.transforms.local_to_telescope_transform()
Transforms photon positions and directions based on a telescope position and orientation.
This kernel performs a coordinate transformation on a set of photons, effectively simulating the observation of those photons by a telescope located at a specific position and with a specific orientation. The transformation consists of a translation and a rotation. Is assumed that the altitude axis is not displaced with respect to the azimuth axis and intersect at the telescope origin.
- Parameters:
ps (float3*) – An array of float3 representing the positions of the photons. Modified in-place.
vs (float3*) – An array of float3 representing the direction vectors of the photons. Modified in-place.
p0 (float3) – A float3 representing the position of the telescope.
r_mat (float*) – A float array representing the rotation matrix.
n_ph (int) – The number of photons to transform.
Attention
This is a wrapped CuPy RawKernel object, you can launch it as follows:
blocks = ... # Number of blocks threads = ... # Number of threads per block shared_memory = ... # Dynamic shared memory buffer size (if needed) args = (...) # Provide the arguments kernel(grid, block, args, shared_mem=shared_memory)
If you are new to CuPy, please see the CuPy documentation.
- iactsim.optics.transforms.pointing_dir(altitude, azimuth)
Telescope pointing direction in the corsika-like local reference frame.
North -> (0, 0) : x-axis
East -> (0, 90)
South -> (0, 180)
West -> (0, 270) : y-axis
Zenith -> (90, any) : z-axis
optics.sources
Classes:
|
Represents a photon source. |
|
Generate a photon spectral distribution. |
|
Generate photon arrival times. |
- class iactsim.optics.sources.Source(telescope=None, dtype=np.float32)
Represents a photon source. By default a point-like source at zenith is generated. Photons are generated at a point (0, 0, 100) m in the local reference frame.
- Parameters:
telescope (IACT | None, optional) – The IACT object associated with this source. If None, the source is assumed to be at a fixed position defined by self.positions.position. Otherwise, a point-like source is generated as a uniform disk, at a coordinates (0, 0, 100) m in the local reference frame, with a radius big enough to illimunate the aperture of the telescope.
dtype (type, optional) – The desired data type for generated quantities, by default np.float32.
Attributes:
Photon arrival times generator.
Photon directions generator.
Photon positions generator.
Photon wavelengths generator.
Methods:
generate(n)Generate n photons.
set_target([target, distance, target_reference])Adjust source position to match the center of a target.
visualize([n_photons, opacity, length, ...])VTK visualization of the source.
- arrival_times: TimeDistribution
Photon arrival times generator.
- directions: AbstractPhotonDirections
Photon directions generator.
- generate(n)
Generate n photons.
- positions: AbstractPhotonPositions
Photon positions generator.
- set_target(target=None, distance=1e5, target_reference='telescope')
Adjust source position to match the center of a target. If the target is not specified, it defaults to the telescope.
- Parameters:
target (int, str, tuple, list, or ndarray, optional) – Name or index of the surface in the telescope optical system, or a specific (x, y, z) coordinate. By default None (telescope position).
distance (float) – Source-target distance in mm.
target_reference (str, optional) – Reference system of the specified target position if a coordinate is provided. Options are ‘telescope’ (default) or ‘global/local’.
- spectrum: Spectrum
Photon wavelengths generator.
- visualize(n_photons=1000, opacity=None, length=None, show_hits=True, show_rays=True, resolution=None)
VTK visualization of the source.
- Parameters:
n_photons (int, optional) – Number of photons to generate, by default 1000.
opacity (float, optional) – Ray opacity, by default None (auto).
length (float, optional) – If provided, rays that not intersects the telescope will be drawn with this length using the direction vector.
show_hits (bool, optional) – Whether to show hits, by default True.
show_rays (bool, optional) – Whether to show rays, by default True.
resolution (float, optional) – Objects mesh resolution (in mm). By default None (depends on object extent).
- Raises:
RuntimeError – If the source is not linked to a telescope.
- class iactsim.optics.sources.Spectrum(dist_type)
Generate a photon spectral distribution.
- Parameters:
dist_type (str) – Distribution type. Supported values are: “uniform”, “constant”, and “cherenkov”.
Attributes:
Data type for generated wavelengths.
Central wavelength (in nm, used only if
typeis "constant").Maximum wavelength (in nm).
Minimum wavelength (in nm).
"uniform", "constant" and "cherenkov".
Methods:
generate(n)Generates wavelength samples based on the specified distribution.
- generate(n)
Generates wavelength samples based on the specified distribution.
- Parameters:
n (int) – The number of samples to generate.
- Returns:
sample – An array of generated wavelength samples.
- Return type:
ndarray
- Raises:
NotImplementedError – If the distribution type is not recognized.
- class iactsim.optics.sources.TimeDistribution(dist_type)
Generate photon arrival times.
- Parameters:
dist_type (str) – Distribution type. Supported values are: “uniform” (i.e. Poissonian) and “constant”.
Attributes:
Data type for generated times.
Central time (in ns, used only if
typeis "constant").End time (in ns).
Start time (in ns).
"uniform" and "constant".
Methods:
generate(n)Generates time samples based on the specified distribution.
- generate(n)
Generates time samples based on the specified distribution.
- Parameters:
n (int) – The number of samples to generate.
- Returns:
sample – An array of generated time samples.
- Return type:
ndarray
- Raises:
NotImplementedError – If the distribution type is not recognized.
Classes:
|
Abstract base class for a photon position generator. |
|
Represents a point source by generating a set of identical 3D points. |
|
Generates uniformly distributed points on a disk (or annulus) parallel to the x-y plane. |
|
Generates uniformly distributed points on a spherical cap. |
- class iactsim.optics.sources.positions.AbstractPhotonPositions(position, rotation=None, dtype=cp.float32, seed=None)
Abstract base class for a photon position generator.
This class defines the interface for generating photon positions in 3D space.
- position
The (x, y, z) coordinates of the point or center of the photon source.
- Type:
cp.ndarray
- rotation
Rotation to be applied to the generated points.
- Type:
cp.ndarray
Methods:
generate(n)Generates photon positions.
- generate(n)
Generates photon positions.
- Parameters:
n (int) – Number of photon positions to generate.
- Returns:
positions – A CuPy array of shape (n, 3) where each row represents a photon position vector (x, y, z).
- Return type:
cp.ndarray
- Raises:
ValueError – If n is not a positive integer.
- class iactsim.optics.sources.positions.PointLike(position, rotation=None, dtype=cp.float32, seed=None)
Represents a point source by generating a set of identical 3D points.
This class creates an array of n identical 3D points, all located at the specified position.
- Parameters:
- Raises:
ValueError – If position is not a 3-element tuple, list, or CuPy array.
- class iactsim.optics.sources.positions.UniformDisk(r_min, r_max, position=cp.asarray([0., 0., 0.]), rotation=None, radial_uniformity=False, random=True, seed=None, dtype=cp.float32)
Generates uniformly distributed points on a disk (or annulus) parallel to the x-y plane.
- Parameters:
r_min (float) – Minimum radius of the disk (or annulus). If r_min > 0, it defines the inner radius of an annulus.
r_max (float) – Maximum radius of the disk (or annulus). Defines the outer radius.
position (array_like, shape (3,)) – Center of the disk (or annulus) in Cartesian coordinates. Can be a list, tuple, NumPy array or CuPy array.
radial_uniformity (bool, optional) – If True (default), uses a radial uniform distribution. If False, uses a uniform distribution in area.
random (bool, optional) – If True (default), generates random points. If False, generates a grid of points.
seed (int | None, optional) – A seed to initialize the random number generator.
dtype (type, optional) – Desired data type of the output array, by default cp.float32.
- Raises:
ValueError – If position does not have a length of 3. If r_min is not >= 0 and less than r_max.
TypeError – If position is not a list, tuple, NumPy array or CuPy array.
- class iactsim.optics.sources.positions.UniformSphericalCap(radius, angular_extent, seed=None, position=cp.asarray([0., 0., 0.]), rotation=None, dtype=cp.float32)
Generates uniformly distributed points on a spherical cap.
The spherical cap is defined by its center (position), radius, and an angular extent (or “opening angle”). Points are uniformly distributed over the cap surface and are generated symmetrically around the z-axis, relative to the center.
- Parameters:
position (array_like, shape (3,)) – The center of the sphere in Cartesian coordinates (x, y, z). Can be a list, tuple, NumPy array or CuPy array.
radius (float) – The radius of the sphere.
angular_extent (float) – The opening angle of the cap in degrees, measured from the positive z-axis. Must be between 0 and 180 degrees.
seed (int | None, optional) – An optional seed for the random number generator. If None, the generator is seeded using unpredictable data from the operating system.
dtype (type, optional) – The desired data type of the returned array (default: np.float32).
- Raises:
ValueError – If angular_extent is not within the range [0, 180]. If position does not have a length of 3.
TypeError – If position is not a list, tuple, or ndarray.
Classes:
|
Abstract base class for a photon source direction generator. |
|
Generates direction vectors with a Gaussian distribution around a central direction. |
|
Generates a set of identical direction vector from a source specified in horizontal coordinates. |
|
Generates uniformly distributed directions within a cone around a central direction. |
- class iactsim.optics.sources.directions.AbstractPhotonDirections(altitude, azimuth, dtype=cp.float32, seed=None)
Abstract base class for a photon source direction generator.
This class defines the interface for generating photon directions, specified by altitude and azimuth angles.
Methods:
generate(n)Generates photon direction vectors.
Attributes:
Seed to initialize the CuPy random number generator (cuRAND Philox4x3210).
- abstractmethod generate(n)
Generates photon direction vectors.
- Parameters:
n (int) – Number of photon directions to generate.
- Returns:
directions – A CuPy array of shape (n, 3) where each row represents a photon direction vector (unit vector).
- Return type:
cp.ndarray
- Raises:
ValueError – If n is not a positive integer.
- property seed
Seed to initialize the CuPy random number generator (cuRAND Philox4x3210).
- class iactsim.optics.sources.directions.GaussianBeam(altitude, azimuth, dispersion, seed=None, dtype=cp.float32)
Generates direction vectors with a Gaussian distribution around a central direction.
This class generates n direction vectors sampled from a Gaussian distribution centered around the direction specified by altitude and azimuth. The spread of the distribution is controlled by dispersion.
- Parameters:
altitude (float) – Altitude angle of the beam center in degrees.
azimuth (float) – Azimuthal angle of the beam center in degrees.
dispersion (float) – Standard deviation (sigma) of the Gaussian distribution in degrees.
seed (int | None, optional) – A seed to initialize the CuPy random number generator (cuRAND Philox4x3210). If None, the generator is seeded using unpredictable data from the operating system.
dtype (data-type, optional) – Desired output data-type. Default is cp.float32.
Methods:
generate(n)Generates the direction vectors sampled from a Gaussian beam.
- generate(n)
Generates the direction vectors sampled from a Gaussian beam.
- Parameters:
n (int) – Number of direction vectors to generate. Must be a positive integer.
- Returns:
vs – An array of n unit vectors representing the directions sampled from the Gaussian beam in a right-handed Cartesian coordinate system.
- Return type:
ndarray, shape (n, 3)
- Raises:
ValueError – If n is not a positive integer.
- class iactsim.optics.sources.directions.PointLike(altitude, azimuth, dtype=cp.float32)
Generates a set of identical direction vector from a source specified in horizontal coordinates.
This class creates an array of n identical unit vectors that represent the direction of a source specified by its altitude and azimuth angles.
- Parameters:
Methods:
generate(n)Generates the set of identical direction vectors.
- generate(n)
Generates the set of identical direction vectors.
- Parameters:
n (int) – Number of identical direction vectors to generate.
- Returns:
vs – An array of n identical unit vectors representing the direction of the source in a right-handed Cartesian coordinate system.
- Return type:
ndarray, shape (n, 3)
- Raises:
ValueError – If n is not a positive integer.
- class iactsim.optics.sources.directions.UniformBeam(altitude, azimuth, half_aperture, dtype=cp.float32, seed=None)
Generates uniformly distributed directions within a cone around a central direction.
This class provides a way to generate n unit vectors that are uniformly distributed within a cone defined by a central direction (altitude, azimuth) and an aperture angle. The distribution is uniform in the sense that the probability of finding a vector within a given solid angle is proportional to that solid angle.
- Parameters:
altitude (float) – Altitude angle of the central direction of the cone (in degrees).
azimuth (float) – Azimuth angle of the central direction of the cone (in degrees).
aperture (float) – Angular half-size (radius) of the cone (in degrees).
dtype (data-type, optional) – Desired data type of the output array, by default cupy.float32
seed (int | None, optional) – A seed to initialize the CuPy random number generator (cuRAND Philox4x3210). If None, the generator is seeded using unpredictable data from the operating system.
Methods:
generate(n)Generates n uniformly distributed direction vectors within the cone.
- generate(n)
Generates n uniformly distributed direction vectors within the cone.
- Parameters:
n (int) – Number of direction vectors to generate.
- Returns:
directions – A CuPy array of shape (n, 3) containing the generated direction vectors. Each row represents a unit vector (x, y, z).
- Return type:
ndarray, shape (n, 3)
- Raises:
ValueError – If n is not a positive integer.
optics.utils
Functions:
Rewrite aspheric coefficients for float32 calculations. |
- iactsim.optics.utils.normalize_aspheric_coefficients(coefficients, half_aperture)
Rewrite aspheric coefficients for float32 calculations.
This function normalizes aspheric coefficients to ensure numerical stability when using single-precision calculations. It scales the coefficients based on the surface aperture radius to prevent potential overflow or underflow issues during calculations involving powers of the radial distance.
- Parameters:
coefficients (numpy.ndarray | list | tuple) – The aspheric coefficients. It can be a NumPy array, a list or a tuple.
half_aperture (float) – The half-aperture of the surface.
- Returns:
new_coefficients – A new array containing the normalized aspheric coefficients.
- Return type:
Notes
The normalization is done by multiplying each coefficient A[i] by ra^(2*(i+1)). This scaling ensures that the coefficients are adjusted appropriately for calculations involving the radial distance, which is typically normalized by the surface half-aperture.
electronics
Classes:
|
Abstract class to simulate a Cherenkov camera. |
|
Base class for a Cherenkov camera that uses Silicon Photo-Multipliers (SiPMs). |
|
Represents the normalized output signal of the electronics in response to a single photon detection as a function of the time from its arrival time. |
- class iactsim.electronics.CherenkovCamera(n_pixels, waveforms, trigger_channels, sampling_channels, channels_time_resolution)
Abstract class to simulate a Cherenkov camera.
- Parameters:
n_pixels (int) – Number of pixels.
waveforms (Union[List[Waveform], Tuple[Waveform]]) – Tuple or List of Waveform instances, one for each channel. Lists are internally converted to a tuple to ensure immutability.
trigger_channels (List[int]) – Trigger channels index.
sampling_channels (List[int]) – Sampling channels index.
channels_time_resolution (List[float]) – Time resolution of each channel.
Notes
Unit Consistency
The simulation does not enforce a specific system of physical units, but it strictly requires internal consistency. It is entirely the user’s responsibility to ensure that all input parameters (time windows, resolutions, rates, etc.) align.
Crucially, rates must be expressed as the number of events per chosen unit of time. For example: if your time inputs are in nanoseconds, rates must be provided in events per ns (i.e. GHz).
Random Seed Handling
The camera manages random number generation for stochastic processes (e.g., cross-talk, background noise) on a per-pixel basis. The seed for each pixel is derived from a single
uint64master seed,base_seed, to ensure reproducibility. This behavior is controlled by the following attributes:base_seed: The master seed that can be set by the user for reproducibility.random_seed: IfTrue(default), a new random value forbase_seedis generated at eachrestart()call. This ensures that different simulation runs are independent. When set toFalse,base_seedis reset to 0.increment_seed: IfTrue(default), thebase_seedis incremented by n_pixels after eachsimulate_response()call. This provides different random sequences for consecutive events within the same run.
If you need to manually update the per-pixel seeds you can increase the
base_seedvalue by n_pixels, in order to have always a different seed per pixel.Auxiliary Channels
Any channel that is not explicitly passed in trigger_channels or sampling_channels is automatically classified as an auxiliary channel. The camera manages their dynamic time windows (via auxiliary_delay and auxiliary_window_extent), but it does not automatically compute their signals. Developers must explicitly request their computation by overriding methods like
sampling_action()orpost_sampling_action()and calling self.compute_signals(self.auxiliary_channels) (or a specific channel needed).Methods:
Apply an ideal discriminator to a specific channel pre-computed signals.
Apply peak detection to a specific channel.
compute_signals([channels])Method to compute signals of each pixel for the desired channels.
get_channel_signals(channel[, reshape])Retrieves the signals for a specified channel.
Optional action that is performed right after the sampling action.
Optional action that is performed right after the trigger action, regardless if a camera trigger is generated.
Compute signals for sampling channels.
Compute signals for trigger channels.
prepare_time_windows([tmin, tmax])Generate dynamic time windows and copy mapping data to the GPU device.
Digitise the signals.
simulate_response([source, tmin, tmax])Simulates the camera response to a given source of photo-electrons.
Generates a camera trigger.
Attributes:
Auxiliary channels list.
Delay of the auxiliary time windows with respect to the camera trigger.
Auxiliary windows extent.
Count rate (background noise) per pixel.
Run-wise seed from wich per-pixel seeds are generated.
Gain of each channel.
Time resolution for each channel.
Whether to enable the camera trigger or skip directly to the sampling phase (in this case a trigger time must be provided).
Whether time windows should be computed for each event or assumed fixed.
Whether to increment the seed at each
simulate_response()call.Number of channels.
Number of pixels in the camera.
Pixel mask.
Whether to generate a random seed.
Sampling channels list.
Delay of the sampling time windows with respect to the camera trigger.
Sampling windows extent.
Computed signals buffer.
Input photo-electrons arrival times.
Time windows where to simulate the signal.
Benchmark timer instance.
Trigger channels list.
Time of the last trigger.
Trigger channels window end offset with respect to the last photo-electron arrival time in
source.Trigger channels window start offset with respect to the first photo-electron arrival time in
source.Whether the camera has been triggered.
Single photo-electron waveform of each channel.
- apply_ideal_discriminator_to_channel(channel, thresholds, offset, time_slices_over_threshold)
Apply an ideal discriminator to a specific channel pre-computed signals.
This method implements an ideal discriminator on the waveforms of a given channel. It compares the input signal against per-pixel thresholds and sets the output signal based on whether the input signal exceeds the threshold for at least a specified number of consecutive time slices.
- Parameters:
channel (int) – The channel number to process.
thresholds (cp.ndarray) – A CuPy 1D array of thresholds, one for each pixel. This array should have a dtype of cp.float32.
offset (cp.ndarray) – A CuPy 1D array of threshold offsets, one for each pixel. This array should have a dtype of cp.float32.
time_slices_over_threshold (int) – The minimum number of consecutive time slices the signal must be above the threshold to trigger a positive output. This value is assumed for all pixels.
- Returns:
A CuPy array of the same shape as the input signal, containing the output of the ideal discriminator. The output will be 0.0f where the signal is below the threshold (or doesn’t stay above threshold long enough) and 1.0f where it is above the threshold.
- Return type:
cp.ndarray
Examples
n_pixels = camera.n_pixels thresholds = cp.random.rand(n_pixels).astype(cp.float32) * 10 offset = cp.zeros((n_pixels), dtype=cp.float32) min_time_slices = 10 channel_num = 0 output_signal = camera.apply_ideal_discriminator_to_channel(channel_num, thresholds, offset, min_time_slices) # output_signal now contains the discriminated signal for channel 0.
- apply_peak_detection_to_channel(peak_amplitudes, peaking_times, channel, t_start, extent)
Apply peak detection to a specific channel.
This method processes the pre-computed signals for a given channel using peak_detection kernel to identify peaks and store their amplitudes and times.
- Parameters:
peak_amplitudes (cp.ndarray) – A CuPy array where the detected peak amplitudes will be stored. This array should be pre-allocated with a size equal to the number of pixels and have a dtype of cp.float32. It can be allocated once as class attribute.
peaking_times (cp.ndarray) – A CuPy array where the detected peaking times will be stored. This array should be pre-allocated with a size equal to the number of pixels and have a dtype of cp.float32. It can be allocated once as class attribute.
channel (int) – The channel number to process.
t_start (float) – The starting time of the peak detection time window (in ns).
extent (float) – The duration of the peak detection time window (in ns).
- Return type:
Examples
n_pixels = camera.n_pixels peak_amps = cp.empty((n_pixels,), dtype=cp.float32) peak_times = cp.empty((n_pixels,), dtype=cp.float32) channel_num = 0 t_start = 0.0 duration = 100.0 camera.apply_peak_detection_to_channel(peak_amps, peak_times, channel_num, t_start, duration) # peak_amps and peak_times now contain the results for channel 0.
- auxiliary_channels
Auxiliary channels list.
- auxiliary_delay
Delay of the auxiliary time windows with respect to the camera trigger. One for each auxiliary channel.
- auxiliary_window_extent
Auxiliary windows extent. One value for each auxiliary channel.
- property background_rate
Count rate (background noise) per pixel.
Can be specified as a single scalar (applied to all pixels) or an array of length n_pixels for per-pixel configuration.
- property base_seed
Run-wise seed from wich per-pixel seeds are generated.
- channels_gain
Gain of each channel.
- channels_time_resolution
Time resolution for each channel.
- abstractmethod compute_signals(channels=None)
Method to compute signals of each pixel for the desired channels.
- Parameters:
channels (list of channel indices) – If None compute signals of all channels. By default None.
Notes
The specific computing logic is left to the concrete implementations. However, implementations should ensure that the signal is only computed for the specified channels and stored in the signals attribute array. If channels is None or empty the method must return immediately.
- enable_camera_trigger
Whether to enable the camera trigger or skip directly to the sampling phase (in this case a trigger time must be provided).
- fixed_time_windows
Whether time windows should be computed for each event or assumed fixed.
- get_channel_signals(channel, reshape=False)
Retrieves the signals for a specified channel.
- Parameters:
- Returns:
A CuPy array containing the signals for the specified channel. The shape of the array depends on the reshape parameter.
- Return type:
cp.ndarray
- Raises:
RuntimeError – If the time window has not been defined for the specified channel.
- increment_seed
Whether to increment the seed at each
simulate_response()call.
- n_channels
Number of channels.
- property n_pixels
Number of pixels in the camera.
- pixel_mask
Pixel mask. Pixel with value 1 are ignored.
- post_sampling_action()
Optional action that is performed right after the sampling action. This method is called only if a trigger condition is met or if the camera trigger is disabled.
- post_trigger_action()
Optional action that is performed right after the trigger action, regardless if a camera trigger is generated. This method is called only if the camera trigger is enabled.
- pre_sampling_action()
Compute signals for sampling channels.
- pre_trigger_action()
Compute signals for trigger channels.
- prepare_time_windows(tmin=None, tmax=None)
Generate dynamic time windows and copy mapping data to the GPU device.
This method manages a two-phase memory and window initialization lifecycle for all camera channels (trigger, sampling, and auxiliary). To maximize performance, it minimizes GPU memory re-allocation overhead by reusing pre-allocated device buffers whenever possible.
- Parameters:
tmin (float or cupy.ndarray, optional) – The minimum photon arrival time for the current event. If None, it is dynamically calculated from the minimum value in self.source[0]. Defaults to None.
tmax (float or cupy.ndarray, optional) – The maximum photon arrival time for the current event. If None, it is dynamically calculated from the maximum value in self.source[0]. Defaults to None.
Notes
The method execution is split into two logical stages based on the
triggeredstatus flag:Pre-Trigger (self.triggered == False): Evaluates bounds for the trigger channels and builds their timeline arrays. For sampling and auxiliary channels, it calculates their anticipated allocation sizes.
Post-Trigger (self.triggered == True): Trigger time is now known. The method loops back through the uninitialized sampling and auxiliary channels to construct their delayed timeline arrays relative to
trigger_time.
When calling
simulate_response()method this function is automatically called before computing trigger signals (i.e. before thepre_trigger_action()call) and before computing sampling signals (i.e. after a trigger and before thepre_sampling_action()call). If you want to implement a simulation pipeline replacingsimulate_response(), remember to call this function before computing trigger signals (when self.triggered == False) and before computing sampling signals (when self.triggered == True).
- property random_seed
Whether to generate a random seed.
- abstractmethod sampling_action()
Digitise the signals.
Notes
The specific logic is left to the concrete implementations. This method is called only if a trigger condition is met or if the camera trigger is disabled.
- sampling_channels
Sampling channels list.
- sampling_delay
Delay of the sampling time windows with respect to the camera trigger. One for each sampling channel.
- sampling_window_extent
Sampling windows extent. One value for each sampling channel.
- signals
Computed signals buffer.
- simulate_response(source=None, tmin=None, tmax=None)
Simulates the camera response to a given source of photo-electrons.
This method controls the simulation process:
Getting the source.
Preparing time windows for trigger channels.
Triggering actions (pre, trigger, post).
Preparing time windows for channels to be sampled.
Sampling actions (pre, sampling, post).
If
enable_camera_triggeris True, thepre_trigger_action(),trigger_action(), andpost_trigger_action()methods are called in sequence.pre_trigger_action()computes the signals of all trigger channels. If a trigger occurs (as determined bytrigger_action()), or if camera triggering is disabled, the sampling phase starts.- Parameters:
source (Tuple[cp.ndarray, cp.ndarray], optional) –
A tuple containing:
pes: A 1D CuPy array of shape (total_n_pes,) containing the arrival times of all photo-electrons.
pes_map: A 1D CuPy array of shape (n_pixels + 1,) representing a mapping to access the arrival times for each pixel. The arrival times for pixel i are given by pes[pes_map[i]:pes_map[i+1]].
If None only the background is simulated.
tmin (float, optional) – Minimum arrival time in source to consider for the dynamic time window generation. If None, the minimum arrival time in source is used. Pass this to avoid device-host synchronization.
tmax (float, optional) – Maximum arrival time in source to consider for the dynamic time window generation. If None, the maximum arrival time in source is used. Pass this to avoid device-host synchronization.
- Raises:
RuntimeError – If camera triggering is disabled (
enable_camera_triggeris False) andtrigger_timeis not set (i.e., is None). This ensures that a valid trigger time is available for the sampling phase.
Notes
The method also increments an event counter (self._event_counter) after each simulation.
If
increment_seedis true, the random seed (base_seed) is incremented byn_pixelsafter each simulation. This helps ensure that the simulation of different events produces different random values (e.g. background and cross-talk generation).The following methods are called during the simulation:
If camera triggering is enabled:
pre_trigger_action(): compute all signals for trigger channels.trigger_action(): Performs the trigger logic (should settriggeredandtrigger_timeattributes).post_trigger_action(): Actions after the trigger.
If
triggeredis True or camera triggering is disabled (and a custom trigger time is provided):pre_sampling_action(): compute all signals for sampling channels (and auxiliary channels ifcompute_auxiliaries_alongside_samplingis True).sampling_action(): Performs the sampling.post_sampling_action(): Actions after sampling.
In both case 1 and 2, methods b,c must be implemented by the user if a base abstract class is used.
- property source
Input photo-electrons arrival times.
- time_windows
Time windows where to simulate the signal. One for each channel.
- timer
Benchmark timer instance.
- abstractmethod trigger_action()
Generates a camera trigger.
Notes
Concrete implementations of this method should contain the logic to determine when a camera trigger has been be generated. If the trigger condition is met, implementations must ensure that:
the triggered attribute is set to True.
the trigger_time attribute is set to the time representing the moment when the trigger condition was met.
This method is called only if the camera trigger is enabled.
- trigger_channels
Trigger channels list.
- trigger_time
Time of the last trigger.
- trigger_window_end_offset
Trigger channels window end offset with respect to the last photo-electron arrival time in
source.
- trigger_window_start_offset
Trigger channels window start offset with respect to the first photo-electron arrival time in
source.
- triggered
Whether the camera has been triggered.
- class iactsim.electronics.CherenkovSiPMCamera(n_pixels, waveforms, trigger_channels, sampling_channels, channels_time_resolution)
Base class for a Cherenkov camera that uses Silicon Photo-Multipliers (SiPMs). Inherits from CherenkovCamera and implements virtual methods specific to SiPMs.
Attributes:
Probability of a microcell generating an afterpulse.
Inverse of the afterpulse time constant.
Optical cross-talk probability between microcells (for example 0.06).
Inverse of the microcell recovery time constant.
Number of microcells per pixel.
Pixel mask array.
Relative standard deviation of the single microcell response amplitude (for example 0.01, i.e. 1%).
Whether to explicitly simulate the finite number of microcells.
Methods:
compute_signals([channels])Compute SiPM signals for the specified channels.
Digitise the signals.
Generates a camera trigger.
- property afterpulse
Probability of a microcell generating an afterpulse.
Can be specified as a single scalar (applied to all pixels) or an array of length n_pixels for per-pixel configuration.
- property afterpulse_inv_tau
Inverse of the afterpulse time constant.
Can be specified as a single scalar (applied to all pixels) or an array of length n_pixels for per-pixel configuration.
- compute_signals(channels=None)
Compute SiPM signals for the specified channels.
- Parameters:
channels (List[int], optional) – Channels IDs, by default computes all channels.
- property cross_talk
Optical cross-talk probability between microcells (for example 0.06).
Can be specified as a single scalar (applied to all pixels) or an array of length n_pixels for per-pixel configuration.
- property inv_tau_recovery
Inverse of the microcell recovery time constant.
Can be specified as a single scalar (applied to all pixels) or an array of length n_pixels for per-pixel configuration.
- property n_ucells
Number of microcells per pixel.
Can be specified as a single scalar (applied to all pixels) or an array of length n_pixels for per-pixel configuration.
- property pixel_mask
Pixel mask array. Pixels with a value of 1 are ignored during processing.
- abstractmethod sampling_action()
Digitise the signals.
Notes
The specific logic is left to the concrete implementations. This method is called only if a trigger condition is met or if the camera trigger is disabled.
- property sigma_ucells
Relative standard deviation of the single microcell response amplitude (for example 0.01, i.e. 1%).
Can be specified as a single scalar (applied to all pixels) or an array of length n_pixels for per-pixel configuration.
- property simulate_ucells
Whether to explicitly simulate the finite number of microcells.
- abstractmethod trigger_action()
Generates a camera trigger.
Notes
Concrete implementations of this method should contain the logic to determine when a camera trigger has been be generated. If the trigger condition is met, implementations must ensure that:
the triggered attribute is set to True.
the trigger_time attribute is set to the time representing the moment when the trigger condition was met.
This method is called only if the camera trigger is enabled.
- class iactsim.electronics.Waveform(time=None, amplitude=None, coupling=None)
Represents the normalized output signal of the electronics in response to a single photon detection as a function of the time from its arrival time. Is assumed to be 0 outside the defined time window.
The waveform is automatically normalized upon initialization based on the provided coupling.
- Parameters:
time (numpy.ndarray) – Array of time values corresponding where the waveform is defined, must be monotonically increasing.
amplitude (numpy.ndarray) – Array of waveform amplitudes corresponding to the time array.
coupling (str) –
Coupling of the signal. Must be “AC” or “DC” (case insensitive). This determines the default normalization scheme applied at initialization:
”AC”: normalize by the waveform peak;
”DC”: normalize by the waveform integral.
Notes
A “dummy” waveform can be created using the default None arguments:
dummy_wave = Waveform()
- Raises:
TypeError – If the input argument are not Numpy ndarray.
ValueError – If the input argument have more than one dimension.
ValueError – If the input argument do not have the same length.
ValueError – If the time array is not monotonically increasing.
ValueError – If the time array is not equispaced.
ValueError – If the signal coupling is not valid.
Attributes:
Returns the amplitude array.
Returns the signal coupling.
Returns the time array.
Methods:
Returns the waveform time-extent.
Returns the approximate integral of the waveform using the trapezoidal rule.
Returns the peak amplitude of the waveform.
Returns the time corresponding to the peak amplitude of the waveform.
get_size()Returns the waveform number of time bins.
Returns the approximate integral of the squared waveform using the trapezoidal rule.
load_json(file_path)Creates a Waveform instance from a JSON file.
normalize([norm])Normalize the waveform amplitude.
save_json(file_path[, comment])Saves the current waveform configuration to a JSON file.
- property amplitude
Returns the amplitude array.
- property coupling
Returns the signal coupling.
- get_integral()
Returns the approximate integral of the waveform using the trapezoidal rule.
- Return type:
- get_peak_time()
Returns the time corresponding to the peak amplitude of the waveform.
- Return type:
- get_squared_integral()
Returns the approximate integral of the squared waveform using the trapezoidal rule.
- Return type:
- classmethod load_json(file_path)
Creates a Waveform instance from a JSON file.
- Parameters:
file_path (str) – Path to the JSON file containing ‘time’, ‘amplitude’, and ‘coupling’.
- normalize(norm=None)
Normalize the waveform amplitude.
This method is automatically called during initialization.
- Parameters:
norm (float, optional) – Normalization factor. If None, it is determined based on the coupling type assigned at initialization. For ‘AC’ coupling, the waveform is normalized to the peak amplitude. For ‘DC’ coupling it’s normalized to the integral. By default, None.
- save_json(file_path, comment='')
Saves the current waveform configuration to a JSON file.
- property time
Returns the time array.
electronics.signals
signals.discriminator_signals
Functions:
Counts the number of rising edges (pixel triggers) in a discriminator signal. |
|
Simulates an ideal discriminator response. |
|
Counts clock cycles between the last pixel trigger and the camera trigger. |
- iactsim.electronics.signals.discriminator_signals.count_pixel_triggers()
Counts the number of rising edges (pixel triggers) in a discriminator signal.
This kernel function takes an array of signals and counts the number of times the signal crosses a threshold (0.5) from below to above, indicating a rising edge or pixel trigger. It operates on a per-pixel basis, processing a window of the signal for each pixel. The kernel assumes ideal rising edges with negligible rising time.
- Parameters:
counts (int*) – An output array of integers, where the count of rising edges for each pixel will be stored. This array should have a size of
n_pixels. The counts are added to the existing values in this array.signals (const float*) – A constant input array of floats representing the signals for each pixel. This array should contain
n_pixelsXwindow_sizeelements, where each pixel signal occupies a contiguous block ofwindow_sizeelements.window_size (int) – An integer representing the size of the window for each pixel signal.
n_pixels (int) – An integer representing the number of pixels to process.
Attention
This is a wrapped CuPy RawKernel object, you can launch it as follows:
blocks = ... # Number of blocks threads = ... # Number of threads per block shared_memory = ... # Dynamic shared memory buffer size (if needed) args = (...) # Provide the arguments kernel(grid, block, args, shared_mem=shared_memory)
If you are new to CuPy, please see the CuPy documentation.
- iactsim.electronics.signals.discriminator_signals.ideal_discriminator()
Simulates an ideal discriminator response.
This kernel processes an input signal and generates a discriminator output signal based on a given threshold. It also applies a minimum pulse width filter.
The kernel operates with one block per pixel. Each thread within a block processes a portion of the pixel time window. Discriminator Logic:
If the
input_signalis above the pixelthresholdAND the pixel is not masked (mask[bid] == 0) theoutput_signalfor that time slice is set to 1.0; otherwise theoutput_signalis set to 0.0. Pulse Width Filter:After the initial discriminator signal is computed, a pulse-width filter is applied within each block (pixel) to search for consecutive time slices where the
output_signalis 1.0. If the number of consecutive slices over threshold is less thantime_slices_over_threshold, those slices in theoutput_signalare reset to 0.0. This effectively removes short pulses. Assumptions/Approximations:Zero rising and falling time.
- Parameters:
input_signal (const float*) – Input signal data with n_pixels X time_window_size elements.
output_signal (float*) – Output discriminator signal data. This array should be pre-allocated with the same size as the relevant portion of the input signal. The array does not need to be initialized.
threshold (const float*) – Threshold value for each pixels. The length of this array should equal
n_pixels.offset (const float*) – Discriminator offset for each pixel. The length of this array should equal
n_pixels.time_slices_over_threshold (int) – Minimum number of consecutive time slices that the input signal must be above the threshold to generate a trigger signal.
mask (const int*) – Array indicating whether a pixel is masked (1) or active (0). Masked pixels will not generate triggers.
time_window_size (int) – The number of time slices in the signal time window.
n_pixels (int) – The total number of pixels.
Attention
This is a wrapped CuPy RawKernel object, you can launch it as follows:
blocks = ... # Number of blocks threads = ... # Number of threads per block shared_memory = ... # Dynamic shared memory buffer size (if needed) args = (...) # Provide the arguments kernel(grid, block, args, shared_mem=shared_memory)
If you are new to CuPy, please see the CuPy documentation.
- iactsim.electronics.signals.discriminator_signals.last_trigger_time_counter_from_camera_trigger()
Counts clock cycles between the last pixel trigger and the camera trigger.
This function simulates a time-to-digital converter (TDC) counter to measure the time between the last trigger of each pixel and the camera trigger. The trigger time for each pixel is determined by counting the number of clock cycles (time bins) between the camera trigger and the last rising edge of the pixel discriminator signal. The counting starts from the beginning of the window and continues up to
stop_clockcycles after the camera trigger clockcamera_trigger_time_index. The result, representing the time difference, is stored as an integer in an array that emulates a register withregister_n_bitsbits (maximum of 32).- Parameters:
trigger_times (int*) – Output array of integers. Stores the calculated trigger times for each pixel. The size of this array should be equal to
n_pixels. Each element represents the time difference in clock cycles, mapped to the range of theregister_n_bits-bit register. A value of 0 indicates no trigger was found within the search window. A value of(2^register_n_bits) - 1indicates an overflow.signals (const float*) – Input array of floats representing the discriminator signals for each pixel. The size of this array should be
n_pixels * window_size. The signal for pixeliis stored insignals[i * window_size]tosignals[(i + 1) * window_size - 1]. A rising edge (transition from < 0.5 to > 0.5) indicates a trigger.camera_trigger_time_index (int) – Integer representing the clock cycle index at which the camera trigger occurs. This serves as the reference time (time 0+2^(register_n_bits-1))) for all pixel trigger time calculations.
stop_clock (int) – Integer representing the number of clock cycles after the camera trigger during which the function will search for pixel triggers. The search window for each pixel is from
camera_trigger_time_indextocamera_trigger_time_index + stop_clock.register_n_bits (int) – Integer representing the number of bits in the simulated TDC register. This determines the range of values that can be stored in
trigger_times. Valid values are between 1 and 32 (inclusive).window_size (int) – Integer representing the number of time bins in the discriminator signal for each pixel.
n_pixels (int) – Integer representing the total number of pixels.
Warning
The function assumes ideal rising edges with a negligible rise time (<<clock).
The function uses shared memory for inter-thread communication within a block.
The size of the shared memory required is
4 * (window_size + blockDim.x)bytes.
Attention
This is a wrapped CuPy RawKernel object, you can launch it as follows:
blocks = ... # Number of blocks threads = ... # Number of threads per block shared_memory = ... # Dynamic shared memory buffer size (if needed) args = (...) # Provide the arguments kernel(grid, block, args, shared_mem=shared_memory)
If you are new to CuPy, please see the CuPy documentation.
signals.sipm_signals
Functions:
Computes the formed SiPM signals. |
- iactsim.electronics.signals.sipm_signals.sipm_signals()
Computes the formed SiPM signals.
This kernel function simulates the response of Silicon Photo-Multipliers (SiPMs) by superimposing single photo-electron (PE) waveforms based on PE arrival time, SiPM cross-talk, SiPM microcells gain dispersion and SiPM PE-background noise. It operates on a per-pixel and per-active-channel basis, assigning a CUDA block per pixel per active channel.
The kernel is launched with a 1D grid of blocks, where each block is responsible for computing the signal for a single (pixel, active_channel) combination. Because the grid only launches for active channels, the block ID (
bid) is a relative index. The kernel internally computesabsolute_idxto correctly index into global arrays spanning all channels. Each block uses shared memory (shared_buffer) to store the intermediate signal, improving performance by reducing global memory accesses.The signal computation involves the following steps:
Determine the block assigned channel and pixel. Initialize the shared memory buffer to zero.
Input signal
2a. Initialize a
curandStatePhilox4_32_10_trandom number generator for the pixel using the provided seed. Each pixel has a unique seed per event. This allows the signals of each channel to be computed in different stages.2b. Iterate through the photon arrival times associated with the current pixel. For each photon:
calculate the number of cross-talk photons using a Borel distribution;
calculate the microcell gain variation, incorporating gain dispersion using a normal distribution;
superimpose the single-photon waveform onto the shared memory buffer, interpolating the channel waveform.
Background signal
3a. Re-initialize the
curandStatePhilox4_32_10_trandom number generator with a seed per thread. 3b. Heach thread generates a background noise event extracting - a number of cross-talk photons; - a micro-cell gain; - a poissoninan inter-arrival time; 3c. The actual time is computed with a parallel cumulative sum of all extracted times. All generated events are stored in shared memory.3d. Generated events are processed one-by-one. The signal accross the time-window is updated in parallel in the shared memory buffer.
Copy the computed signal from the shared memory buffer to the global
signalsarray.
- Parameters:
windows (const float*) – Array of time windows for each channel. Defines the time ranges over which signals are computed.
windows[windows_map[channel] : windows_map[channel+1]]is the time window forchannel.windows_map (const int*) – Array indicating the starting and ending index of the time window for each channel within the
windowsarray.signals (float*) – Output array where the computed SiPM signals are stored. The signal for a given channel and pixel is stored in a contiguous block.
signals[start_signals[channel] + pixel_id * n_window : start_signals[channel] + (pixel_id + 1) * n_window]where n_window = windows_map[channel+1] - windows_map[channel]. The array does not need to be initialized before the kernel invocation.signals_map (const int*) – Array indicating the starting index and ending index of each channel inside the array signals.
active_channels (const int*) – Array of channel IDs to actually compute (e.g., [1, 2]).
n_active_channels (int) – Length of the active_channels array (e.g., 2).
n_channels (int) – Total number of channels in the camera geometry.
t0s (const float*) – Array of discharge times for each pixel.
map (const int*) – Array that maps pixel indices to the range of their corresponding discharge times in the
t0sarray. Specifically,t0s[map[pixel_id]:map[pixel_id+1]]provides the discharge times forpixel_id.waveforms (Unknown) – Array containing the texture pointer of all channel waveforms.
inv_dt_waveforms (const float*) – Array containing the inverse of the time spacing (dt) for each waveform.
t_start_waveforms (const float*) – Array indicating the starting time of each waveform.
gains (const float*) – Array containing the pulse peak amplitued for each pixel for each channel (n_pixels*n_channels size)
xt (const float*) – Array of cross-talk probabilities for each pixel. This represents the probability that a discharge in one microcell will trigger a discharge in an adjacent microcell.
std_ucells (const float*) – Array of microcell gain dispersions for each pixel. This models the variation in the charge produced by different microcells for a single photon.
mask (const int*) – Array indicating whether a pixel is masked (1) or active (0). Masked pixels will have zero signal.
inv_bkg_rate (const float*) – Array of inverse background rates for each pixel (in units of time). This is used to generate background noise events.
bkg_start (float) – Start time for background noise generation.
bkg_end (float) – End time for background noise generation.
seed (unsigned long long) – Array of random number generator seeds, one for each pixel.
n_pixels (int) – Number of pixels.
Warning
The number of blocks must be
n_pixels*n_active_channels(i.e. a block per pixel per active channel).The size of the shared memory buffer must be equal to
(max_window_size+n_threads*3 + 32) * sizeof(float).
Attention
This is a wrapped CuPy RawKernel object, you can launch it as follows:
blocks = ... # Number of blocks threads = ... # Number of threads per block shared_memory = ... # Dynamic shared memory buffer size (if needed) args = (...) # Provide the arguments kernel(grid, block, args, shared_mem=shared_memory)
If you are new to CuPy, please see the CuPy documentation.
signals.sampling_signals
Functions:
Digitizes 16-bit signals and adds digitization baseline and noise. |
|
Detects the peak value and its corresponding time within a specified time interval for each pixel. |
- iactsim.electronics.signals.sampling_signals.digitize()
Digitizes 16-bit signals and adds digitization baseline and noise.
This kernel performs digitization of floating-point input signals, simulating the behavior of an Analog-to-Digital Converter (ADC). It also adds digitization Gaussian noise to the digitized signal.
- Parameters:
digitized_output (unsigned short*) – Pre-allocated output array to store the digitized signals. Size:
n_pixels * time_window_size. The data type isunsigned short, representing the 16-bit digitized values. The array does not need to be initialized.input_signals (const float*) – Input array containing the floating-point signal data for all pixels. Size:
n_pixels * time_window_size.offset (const float*) – Input array containing the baseline of the digitised signal for each pixel.
noise (const float*) – Input array containing the per-pixel noise factors. Size:
n_pixels. These values scale the standard deviation of the normally distributed noise added to each pixel.seed (unsigned long long) – Input array of seeds for the per-pixel pseudo-random number generators. Size:
n_pixels. Using different seeds for each pixel ensures uncorrelated noise.adc_max (int) – The maximum value that the ADC can represent (saturation level). This should correspond to the maximum value of 2^n-1 for a n-bit ADC (up to 16-bit).
n_pixels (int) – The total number of pixels.
time_window_size (int) – The number of time samples in the time window (i.e.: the number of samples per pixel in the
input_signalsanddigitized_outputarrays).
Notes
The data (
digitized_outputandinput_signals) is organized such that all time samples for pixel 0 are contiguous, followed by all time samples for pixel 1 and so on.Attention
This is a wrapped CuPy RawKernel object, you can launch it as follows:
blocks = ... # Number of blocks threads = ... # Number of threads per block shared_memory = ... # Dynamic shared memory buffer size (if needed) args = (...) # Provide the arguments kernel(grid, block, args, shared_mem=shared_memory)
If you are new to CuPy, please see the CuPy documentation.
- iactsim.electronics.signals.sampling_signals.peak_detection()
Detects the peak value and its corresponding time within a specified time interval for each pixel.
This kernel function implements a parallel peak detection algorithm. The algorithm searches for the maximum signal value within a peak-detection window for each pixel. This peak-detection window is a sub-interval of the global time window covered by the entire signal.
The algorithm works as follows:
The kernel uses one block per pixel. Each thread within a block is responsible for processing a sub-window of the global time window, defined by the
time_windowarray.Threads within a block cooperate using shared memory. Each thread finds the maximum value within its assigned sub-window of the global time window and stores it, along with the corresponding time, in shared memory.
A reduction is performed to find the maximum of these intermediate maxima (from shared memory) in order to determine the global peak for the pixel within the specified peak-detection window [t_start, t_start+extent].
For each pixel the peak value and its corresponding time are written to global memory arrays. The global time window is represented by the
time_windowarray, which contains the time values for all signals. The peak-detection window is defined by thet_startandextentparameters. The peak is searched for only within the interval[t_start, t_start + extent]. This allows for focused peak detection within a specific region of interest. The global time window is divided among the available threads. Each thread finds a sub-window maximum and stores it in a shared arrayth_peaks_and_times. Thread 0 then finds the maximum ofth_peaks_and_timesand stores the result in the global memory arrayspeak_amplitudesandpeak_time. The shared array is allocated dynamically. The total shared memory needed is 8 * blockDim.x bytes (2 floats per thread).
- Parameters:
peak_amplitudes (float*) – Output array to store the peak signal values for each pixel. Size:
n_pixels.peak_time (Unknown) – Output array to store the time corresponding to the peak signal for each pixel. Size:
n_pixels.signals (const float*) – Input array containing the signal data for all pixels. The data is organized such that all time samples for pixel 0 are contiguous, followed by all time samples for pixel 1, and so on. Size:
n_pixels * time_window_size.time_window (const float*) – Input array containing the time values corresponding to each sample in the
signalsarray. This defines the global time window. Size:time_window_size.t_start (float) – The start time of the peak-detection window.
extent (float) – The duration (extent) of the peak-detection window, starting from
t_start. The peak is searched for within[t_start, t_start + extent].mask (const int*) – Input array acting as a mask. Pixels with a mask value of 1 are skipped (peak=0 and time=0). Size:
n_pixels.time_window_size (int) – The number of time samples in the
time_windowarray (and the number of samples per pixel in thesignalsarray). This represents the size of the global time window.n_pixels (int) – The total number of pixels.
Warning
The number of blocks must be at least n_pixels (i.e. a block per pixel).
The number of threads must be a power of 2.
The size of the dynamic shared memory buffer must be two times the number of thread assigned to each block multiplied by 4 (i.e. 8 bytes per thread).
Attention
This is a wrapped CuPy RawKernel object, you can launch it as follows:
blocks = ... # Number of blocks threads = ... # Number of threads per block shared_memory = ... # Dynamic shared memory buffer size (if needed) args = (...) # Provide the arguments kernel(grid, block, args, shared_mem=shared_memory)
If you are new to CuPy, please see the CuPy documentation.
signals.trigger_logic
Functions:
Counts the number of camera triggers within a time window. |
|
Computes topological triggers for the entire camera and identifies the earliest trigger time and module. |
- iactsim.electronics.signals.trigger_logic.count_topological_camera_triggers()
Counts the number of camera triggers within a time window.
This kernel computes a global camera trigger signal by performing a logical OR operation across all module trigger signals for each time slice. If any module is triggered at time
t(signal > 0.5), the camera is considered triggered at timet. After constructing this global signal in shared memory, the kernel identifies and counts the number of rising edges (transitions from logical 0 to 1). The kernel is designed to operate within a single thread block.- Parameters:
counts (int*) – Pointer to an integer global counter. The detected number of triggers is added to this value using atomic operations. Ensure this is initialized to 0 before use.
signals (const float*) – Pointer to the global array of module trigger signals. Layout is assumed to be
[n_modules * window_size], accessed assignals[module_idx * window_size + time_idx].window_size (int) – The number of time slices in the time window.
n_modules (int) – The total number of modules in the camera.
Warning
Shared Memory: this kernel requires dynamic shared memory. The kernel launch must allocate at least
window_size * sizeof(float)bytes of dynamic shared memory.Single Block: this kernel explicitly checks
blockIdx.x. Computation only occurs in Block 0. Launching withgridDim.x > 1is valid but wasteful.Edge Cases: a rising edge is defined as
signal > 0.5andprevious <= 0.5.countsmust be initialized to 0 before kernel launch.
Attention
This is a wrapped CuPy RawKernel object, you can launch it as follows:
blocks = ... # Number of blocks threads = ... # Number of threads per block shared_memory = ... # Dynamic shared memory buffer size (if needed) args = (...) # Provide the arguments kernel(grid, block, args, shared_mem=shared_memory)
If you are new to CuPy, please see the CuPy documentation.
- iactsim.electronics.signals.trigger_logic.topological_camera_trigger()
Computes topological triggers for the entire camera and identifies the earliest trigger time and module.
This kernel processes the discriminator signals for all modules in parallel. Each thread block handles a specific module (determined by
blockIdx.x), and threads within the block iterate over the time window in a grid-stride loop. For every time slice, the kernel checks if the module satisfies the topological trigger condition (a contiguous group of active pixels >=n_contiguous) usingmodule_topological_trigger. The kernel performs two main outputs:Signal Generation: Populates
module_trigger_signalswith a 1.0/0.0 trace indicating trigger status for every module and time step.Global Trigger Identification: Finds the earliest trigger occurrence across the entire camera.
It uses atomic operations to find the global minimum of a packed 64-bit integer encoding
(Time << 32) | (RandomSkip << 16) | (ModuleID)The “RandomSkip” is used to chose randomly a module when multiple modules trigger at the exact same time, preventing bias toward lower module IDs.
The result is unpacked into the
triggerinput array.
- Parameters:
disc_signals (float*) – Pointer to the global signal array with layout
[n_modules * n_pixels * window_size]. Contains the raw discriminator outputs (float).n_contiguous (int) – The minimum number of contiguous pixels required to form a trigger.
module_trigger_signals (float*) – Output array of size
[n_modules * window_size]. Stores the binary trigger result (1.0 or 0.0) for each module/time.trigger (int*) – Output array of size 2 (int): -
trigger[0]: Time index of the earliest trigger (or -1 if none); -trigger[1]: Module ID of the earliest trigger (or -1 if none).workspace (Unknown) – Global memory buffer for DFS operations. Must be large enough to hold stack and mask data for every thread. Size:
n_modules * n_threads * (n_pixels + n_pixels/32 + 2).window_size (int) – The length of the readout window (number of time slices).
module_dimension (int) – The width/height of a module (e.g., 8).
n_modules (int) – Total number of modules in the camera.
seed (long long int) – Seed for the random number generator used to randomly pick a module ID when multiple modules trigger at the same time.
Warning
workspace_buffermust have a size ofn_modules * n_threads * (n_pixels + n_pixels/32 + 2).
Notes
This kernel requires
cg::sync(grid)and thus must be launched using a cooperative launch API if the grid size exceeds the device’s maximum resident blocks, or if global synchronization is strictly required. However, the current implementation only strictly requires grid sync for the final unpacking step on thread 0.Attention
This is a wrapped CuPy RawKernel object, you can launch it as follows:
blocks = ... # Number of blocks threads = ... # Number of threads per block shared_memory = ... # Dynamic shared memory buffer size (if needed) args = (...) # Provide the arguments kernel(grid, block, args, shared_mem=shared_memory)
If you are new to CuPy, please see the CuPy documentation.
electronics.sources
Functions:
|
Generate Poisson arrival times in a time window equal for all pixels. |
- iactsim.electronics.sources.generate_poisson_flash(n_pixels, mean, t_start, duration, n_ucells=None, seed=None)
Generate Poisson arrival times in a time window equal for all pixels.
This function simulates the arrival times of photo-electrons generated by a Poisson process, representing a light flash. It assumes the same time window (start time and duration) for all pixels, but allows for a different mean number of photo-electrons for each pixel.
- Parameters:
n_pixels (int) – Total number of pixels.
mean (Union[cp.ndarray, numpy.ndarray]) – Mean number of photo-electrons for each pixel. This should be a 1D array of length n_pixels.
t_start (float) – Start time of the flash (in ns).
duration (float) – Duration of the flash (in ns).
get_ucells_id (int, optional) – Number of micro-cells per pixel micro-cell IDs (for microcell simulation).
seed (int, optional) – Random seed for reproducibility. If None, a random seed is generated.
- Returns:
A tuple containing:
pes: A 1D CuPy array of shape (total_n_pes,) containing the arrival times of all photo-electrons.
pes_map: A 1D CuPy array of shape (n_pixels + 1,) representing a mapping to access the arrival times for each pixel. The arrival times for pixel i are given by pes[pes_map[i]:pes_map[i+1]].
- Return type:
Tuple[cp.ndarray, cp.ndarray]
Examples
import cupy as cp n_pixels = 10 mean = cp.array([2.0, 3.5, 1.0, 4.2, 0.8, 2.7, 1.9, 3.1, 2.5, 1.3]) t_start = 0.0 duration = 10.0 pes, pes_map = generate_poisson_flash(n_pixels, mean, t_start, duration) # Access arrival times for pixel 3: pixel_3_times = pes[pes_map[3]:pes_map[4]]
electronics.utils
Classes:
|
Stores photon-to-pixel mappings and arrival times for camera simulation. |
- class iactsim.electronics.utils.CameraInputData(phs, pe_event_pixel_offsets, pe_event_offsets, t_min, t_max, subids=None)
Stores photon-to-pixel mappings and arrival times for camera simulation. All initialization parameters are stored as public attributes of the same name.
This class acts as a sequence, allowing users to easily iterate over or index individual events. It holds the intermediate arrays generated after photon tracing, enabling deferred or batched execution of the camera response simulation.
- Parameters:
phs (cupy.ndarray) – 1D array containing the arrival times of all detected photo-electrons across all events.
pe_event_pixel_offsets (cupy.ndarray) – 2D array of shape (n_events, n_pixels + 1). Contains the cumulative sum of photoelectrons per pixel for each event.
pe_event_offsets (cupy.ndarray or numpy.ndarray) – 1D array of shape (n_events + 1,). Contains the global starting and ending indices for each event slice in the phs array.
t_min (cupy.ndarray) – 1D array of shape (n_events,) containing the minimum arrival time for each event.
t_max (cupy.ndarray) – 1D array of shape (n_events,) containing the maximum arrival time for each event.
subids (cupy.ndarray, optional) – 1D array of sub-pixel IDs corresponding to each photoelectron in phs. Required if microcell simulation is enabled. Default is None.
- simulate_ucells
Flag indicating whether microcell simulation data (subids attribute) is present.
- Type:
- pe_event_offsets_host
A host copy of pe_event_offsets to allow fast indexing in Python loops without triggering device-to-host synchronizations.
- Type:
Examples
Simulate the detection of a specific event:
Loop over filtered events:
Methods:
__getitem__(event_idx)Retrieve the source arrays and timing bounds for a specific event.
__iter__()Iterate over the active events.
__len__()Get the total number of events stored in the input data.
__repr__()Generate a text-based table representation of the class statistics.
apply_pes_threshold(min_n_pes)Filter the internal events based on a minimum photoelectron threshold.
get_event_photons(event_idx[, active_only])Extract the photon data for all pixels in a specific event.
get_pixel_photons(event_idx, pixel_idx)Extract the arrival times (and sub-pixel IDs) for a specific pixel.
Attributes:
Get the number of events that passed the pes threshold.
- __getitem__(event_idx)
Retrieve the source arrays and timing bounds for a specific event.
- Parameters:
event_idx (int) – The index of the event to retrieve.
- Returns:
A tuple containing (source, t_min, t_max). source is itself a tuple of arrays required by the camera simulation: (phs_slice, pixel_offsets_slice) or (phs_slice, pixel_offsets_slice, subids_slice) if microcells are enabled. t_min and t_max are the scalar time bounds for the event.
- Return type:
- Raises:
IndexError – If the event_idx is out of bounds.
- __iter__()
Iterate over the active events. If no threshold has been applied, it defaults to iterating over all events.
- Yields:
tuple – (original_event_idx, source, t_min, t_max)
- __len__()
Get the total number of events stored in the input data.
- Returns:
The number of events.
- Return type:
- __repr__()
Generate a text-based table representation of the class statistics.
- Returns:
Formatted ASCII table containing object statistics.
- Return type:
- apply_pes_threshold(min_n_pes)
Filter the internal events based on a minimum photoelectron threshold. Sets the self.active_indices attribute for iteration.
- get_event_photons(event_idx, active_only=True)
Extract the photon data for all pixels in a specific event.
- Parameters:
- Returns:
A dictionary mapping pixel_idx (int) to its photon data. The photon data format matches get_pixel_photons (either an array of times, or a tuple of (times, subids)).
- Return type:
- get_pixel_photons(event_idx, pixel_idx)
Extract the arrival times (and sub-pixel IDs) for a specific pixel.
- Parameters:
- Returns:
If microcells are disabled, returns a 1D array of arrival times. If microcells are enabled, returns a tuple of (arrival_times, subids).
- Return type:
- property n_active_events
Get the number of events that passed the pes threshold.
io
Classes:
|
Custom YAML dumper that formats Path objects with the |
|
Custom YAML loader that resolves file paths relative to the configuration file location. |
- class iactsim.io.PathDumper(stream, **kwargs)
Custom YAML dumper that formats Path objects with the
!pathtag.If the Path object is absolute, this dumper will automatically attempt to make it relative to the directory of the file being written to.
- class iactsim.io.PathLoader(stream)
Custom YAML loader that resolves file paths relative to the configuration file location.
This loader enables the use of the
!pathtag in YAML files. When this tag is encountered, the loader automatically resolves the specified path relative to the directory containing the YAML file, returning a pathlib.Path object.
visualization
Classes:
|
Class to viasualize the geometry of an optical system. |
Functions:
|
An interactive widget to browse camera images or call a custom plotting function. |
|
Plots an image of the camera using true pixel positions and shapes, mapping a 1D array of pixel values to a colormap. |
|
Generates and displays a 2D histogram of two components of a set of 3D vectors. |
|
Creates a scatter plot of two components of a set of 3D vectors. |
- class iactsim.visualization.VTKOpticalSystem(optical_system, resolution=None)
Class to viasualize the geometry of an optical system. Each surface actor can be accessed from
actorsattribute after aupdate()call.- Parameters:
optical_system (OpticalSystem or IACT) – Optical sistem for which visualize surfaces.
resolution (float, optional) – Objects mesh resolution (in mm). By default 10 mm.
Notes
If you perform some operation on an actor, make sure to call
start_render()withupdate=False, otherwise the actors will be replaced.Attributes:
surface actor.
Window size in pixel.
Whether to use wireframe representation by default.
Methods:
add_rays(start, stop[, surface_id, ...])Draw rays from start to stop positions and highlight stop points.
get_screenshot(camera_position[, filename, ...])Render the scene off-screen and save it to a PNG file.
set_ray_opacity(value)Set the opacity of rays.
start_render([camera_position, focal_point, ...])Render the optical system geometry on a VTK window.
- actors
surface actor.
- Type:
Dictionary of surface name
- add_rays(start, stop, surface_id=None, wavelengths=None, directions=None, length=None, point_size=1.0, show_rays=True, show_hits=True)
Draw rays from start to stop positions and highlight stop points.
If a stop position is NaN (indicating a miss), the ray is skipped by default. If ‘length’ and ‘directions’ are provided, rays with NaN stops are drawn starting from ‘start’ along ‘direction’ for ‘length’ units (without a hit dot).
- Parameters:
start (ndarray) – (n, 3) array of starting coordinates (x, y, z).
stop (ndarray) – (n, 3) array of stopping coordinates (x, y, z).
surface_id (ndarray) – (n,) array of surface indices reached by each ray.
directions (ndarray, optional) – (n, 3) array of direction vectors. Required if plotting NaN rays with fixed length.
length (float, optional) – If provided, rays with NaN stop will be drawn with this length using the direction vector.
opacity (float, optional) – Transparency of the rays from 0.0 (invisible) to 1.0 (opaque). Default is 0.5.
point_size (float, optional) – Size of the hit points. Default is 1.0
show_rays (bool, optional) – Whether to show rays or not. Default is True.
show_hits (bool, optional) – Whether to show hits or not. Default is True.
- get_screenshot(camera_position, filename=None, focal_point=None, view_up=(0, 0, 1), size=None, image_scale=1, orthographic=False, representation='surface', hide_surfaces=None, zoom=1.0, show=False, position_reference='telescope', position_shift=(0, 0, 0))
Render the scene off-screen and save it to a PNG file.
Coordinates for camera position, focal point, and view up should be provided in the telescope coordinate system. The method handles the transformation to the local coordinate system automatically.
- Parameters:
camera_position (sequence of float) – The (x, y, z) coordinates of the camera position. The reference frame can be specified with the position_reference parameter.
filename (str, optional) – Path to save the resulting PNG file. If None, the screenshot is not saved.
focal_point (str or sequence of float, optional) – The point the camera is looking at. - If None (default): The camera looks at the center of the bounding box of all system actors. - If str: Looks for an optical surface with this name and targets its position. - If sequence: Uses the provided (x, y, z) coordinates (assumend to be local coordinates).
view_up (sequence of float) – The vector defining the “up” direction for the camera, default=(0, 0, 1).
size (tuple of int, optional) – The (width, height) of the rendered image in pixels. If None, uses the current window size.
image_scale (int) – Resolution multiplier (e.g., 2 doubles the pixel density), default=1.
orthographic (bool) – If True, uses parallel projection. If False, uses standard perspective projection. By default False.
representation ({'surface', 'wireframe', 'points'}) – The rendering style of the actors in the scene, default=’surface’.
hide_surfaces (list of str, optional) – A list of names of surfaces/actors to exclude from the render.
zoom (float) – Zoom factor applied when
orthographicis True. - 1.0: Fits the object diagonal to the screen height. - > 1.0: Zooms in. - < 1.0: Zooms out. By default 1.0. Note: This parameter currently implies no effect if orthographic is False.show (bool) – If True, displays the image using Matplotlib. Default is False.
position_reference – Reference system of the specified camera position, by default ‘telescope’. If does not starts with ‘t’, the camera position is assumed to be relative to the local reference system.
- Returns:
RGB image array with shape (height, width, 3).
- Return type:
- start_render(camera_position=None, focal_point=None, view_up=(0, 0, 1), orthographic=False)
Render the optical system geometry on a VTK window.
- Parameters:
camera_position (tuple or list, optional) – (x, y, z) coordinates for the camera position.
focal_point (tuple, list, or str, optional) – If tuple/list: (x, y, z) coordinates to look at. If str: The name of the surface in self.os to look at. If None: Defaults to center of system.
view_up (tuple or list, optional) – (x, y, z) vector defining the “up” direction. Default is (0, 0, 1).
orthographic (bool, optional) – If True, start with a parallel projection. If False, start with a perspective projection. Default is False.
- window_size
Window size in pixel.
- wireframe
Whether to use wireframe representation by default.
- iactsim.visualization.browse_images(image_lists=None, geom=None, cmaps=None, vmins=None, vmaxs=None, titles=None, plot_kwargs=None, prefix='event', plot_function=None, where=None)
An interactive widget to browse camera images or call a custom plotting function.
This function generates a Jupyter-compatible interactive UI with a slider and navigation buttons to step through camera events. It supports rendering either a single image stream, comparing multiple image streams side-by-side in synchronized subplots, or rendering custom figure logic.
If a plotting function is provided, it will be called with each item from the where iterable to generate a custom figure. Otherwise, the function will use camerashow to render images from the provided lists.
- Parameters:
image_lists (array_like or list of array_like, optional) – A single list/array of images, or a list containing multiple lists of images to be plotted side-by-side. Required if plot_function is None.
geom (object, optional) – The camera geometry object required by the camerashow backend. Required if plot_function is None. cmaps : str or list of str, optional The colormap(s) to use. If a single string is provided alongside multiple image lists, the colormap is applied to all plots. Default is ‘viridis’.
vmins (float or list of float, optional) – The minimum data value(s) that correspond to the lower end of the colormap. If a single value is provided alongside multiple image lists, the value is applied to all plots. If None, it dynamically updates based on the current image minimum value. Default is None.
vmaxs (float or list of float, optional) – The maximum data value(s) that correspond to the upper end of the colormap. If a single value is provided alongside multiple image lists, the value is applied to all plots. If None, it dynamically updates based on the current image maximum value. Default is None.
titles (str or list of str, optional) – The title(s) to display above each subplot. The event index is automatically appended (e.g., “Title - Event 0”). If a single string is provided alongside multiple image lists, the title is applied to all plots. Defaults to None.
plot_kwargs (dict or list of dict, optional) – Additional keyword arguments (e.g., {‘show_axes’: True, ‘colorbar’: False}) to pass directly to the underlying camerashow function. If a single dictionary is passed, it applies to all subplots.
prefix (str, optional) – The prefix used for the filename when clicking the “Save” button. Default is “event”.
plot_function (callable, optional) – A custom function that takes a single argument (an item from where) and returns a matplotlib Figure. If provided, standard plotting is bypassed.
where (iterable, array_like, or boolean mask, optional) – If plot_function is provided, this is an iterable of items passed into it. If plot_function is None, this acts as a mask or index array to filter all image lists before plotting.
- Raises:
RuntimeError – If the function is executed outside of an IPython/Jupyter notebook.
ValueError – If inputs are invalid or misaligned. If plot_function is provided without a corresponding where iterable. If image_lists and geom are not provided when plot_function is None. If the where mask filters out all images, resulting in an empty list. If the inner lists in image_lists have different lengths after filtering.
- iactsim.visualization.camerashow(image, geom, ax=None, figsize=None, cmap='viridis', vmin=None, vmax=None, colorbar=True, show=False, rasterized=True, show_axes=False, interactive_tooltip=True)
Plots an image of the camera using true pixel positions and shapes, mapping a 1D array of pixel values to a colormap.
- Parameters:
image (numpy.ndarray or cupy.ndarray) – A 1D or 2D array, with N elements, containing the values to plot for each pixel. It is assumed that the array index corresponds to the pixel ID (0 to N-1).
geom (CameraGeometry) – The camera geometry object containing pixel positions and shapes.
ax (matplotlib.axes.Axes, optional) – The axis on which to plot. If None, a new figure and axis are created.
figsize (tuple, optional) – The size of the figure to create if ax is None. Defaults to None.
cmap (str or matplotlib.colors.Colormap, optional) – The colormap to use for mapping the image values. Defaults to ‘viridis’.
vmin (float, optional) – The minimum data value that corresponds to the lower end of the colormap. If None, the minimum of the image array is used.
vmax (float, optional) – The maximum data value that corresponds to the upper end of the colormap. If None, the maximum of the image array is used.
colorbar (bool, optional) – If True, adds a colorbar to the figure. Defaults to True.
show (bool, optional) – If True, calls plt.show() at the end of the function. Defaults to False.
rasterized (bool, optional) – If True, rasterizes the patch collection when saving to vector formats to prevent artifacts. Defaults to True.
show_axes (bool, optional) – If True, displays the x and y axes with labels. Defaults to False.
interactive_tooltip (bool, optional) – If True, enables a hover tooltip showing the pixel ID and value. Defaults to True.
- Returns:
ax (matplotlib.axes.Axes) – The axis containing the plot.
collection (matplotlib.collections.PatchCollection) – The generated patch collection (useful for updating data in animations).
cax (matplotlib.axes.Axes or None) – The axis containing the colorbar, or None if colorbar=False.
- iactsim.visualization.histogram2d(vectors3d, bins, plane='xy', to_weight=None, dx=None, ax=None, scale=1., norm=None, range=None, update_this=None, log=False, vmin=None, vmax=None, cmap='viridis', interpolation='nearest', colorbar=True, cbar_label=None, title=None, xlabel=None, ylabel=None, **kwargs)
Generates and displays a 2D histogram of two components of a set of 3D vectors.
- Parameters:
vectors3d (numpy.ndarray) – A NumPy array representing a set of 3D vectors. The first two columns are used as x and y coordinates for the histogram. The third column is ignored.
bins (int or array_like) – The number of bins or the bin edges (see numpy.histogram2d documentation for details).
plane (str) – String representation of the components to plot, e.g.: ‘xy’, ‘zy’, ‘zx’, etc.
to_weight (numpy.ndarray, optional) – Weights for each vector. If None, all vectors are weighted equally.
dx (float, optional) – Determines the range if range is not explicitly provided. Defines a square region around the data center with sides of length 2*dx.
ax (matplotlib.axes.Axes, optional) – An Axes object to plot on. If None, the current axes (plt.gca()) is used.
scale (float, optional) – Scaling factor applied to x and y coordinates.
norm (matplotlib.colors.Normalize, optional) – Normalization instance for histogram data (e.g., colors.LogNorm for logarithmic scaling).
range (sequence, optional) – A sequence of (min, max) pairs for each dimension, specifying the data range to be histogrammed.
update_this (numpy.ndarray, optional) – A 2D array (another histogram) to be added to the calculated histogram.
log (bool, optional) – If True, applies a log1p transformation (log(1 + x)) to the histogram counts.
vmin (float, optional) – Minimum value for colormap scaling.
vmax (float, optional) – Maximum value for colormap scaling.
cmap (str, optional) – The colormap to use.
interpolation (str, optional) – Interpolation method used by imshow.
colorbar (bool, optional) – Whether to add a colorbar.
cbar_label (str, optional) – Label for the colorbar.
title (str, optional) – Title of the plot.
xlabel (str, optional) – Label for the x-axis.
ylabel (str, optional) – Label for the y-axis.
**kwargs – Additional keyword arguments passed to numpy.histogram2d.
- Returns:
H (numpy.ndarray) – The 2D histogram array.
im (matplotlib.image.AxesImage) – The image object returned by imshow.
Examples
>>> data = np.random.randn(1000, 3) >>> H, im = histogram2d(data, bins=50, log=True, title="2D Histogram") >>> plt.show()
>>> weights = np.random.rand(1000) >>> H, im = histogram2d(data, bins=50, to_weight=weights, cbar_label="Average Weight") >>> plt.show()
- iactsim.visualization.scatter(vectors3d, colors_array=None, plane='xy', s=0.1, marker=None, ax=None, scale=1., cbar=True, **kwargs)
Creates a scatter plot of two components of a set of 3D vectors.
- Parameters:
vectors3d (array_like) – A numpy.ndarray or list of 3D vectors. The shape should be (N, 3), where N is the number of vectors.
colors_array (array_like, optional) – An numpy.ndarray of color values for each point. Can be a list of color names, a list of RGB/RGBA tuples, or a 1D array of numerical values to be mapped to colors using a colormap.
plane (str) – String representation of the components to plot, e.g.: ‘xy’, ‘zy’, ‘zx’, etc.
s (float, optional) – The marker size in points**2 (default: 0.1).
marker (str, optional) – The marker style (default: None, which uses the default marker style from matplotlib). See matplotlib.markers for valid marker styles.
ax (matplotlib.axes.Axes, optional) – The axes on which to plot. If None, the current axes are used (plt.gca()).
scale (float, optional) – A scaling factor applied to the x and y coordinates (default: 1.).
cbar (bool, optional) – Whether to add a colorbar (default: True). The colorbar will only be added if colors_array is also provided and is a list or NumPy array.
**kwargs – Additional keyword arguments passed to matplotlib.pyplot.scatter. This allows for customization of the plot, such as setting the colormap (‘cmap’), edgecolors (‘edgecolors’), etc.
- Returns:
cax – The axes of the colorbar if a colorbar is created; otherwise, None.
- Return type:
matplotlib.axes.Axes or None
utils
Classes:
A class to time and manage benchmark results organized in "sections" and "measurements". |
Functions:
|
Converts Doxygen-style documentation within the given source code to NumPy-style docstrings. |
|
Get kernel wrapper. |
|
Generates wrapper function for a CuPy RawKernel. |
- class iactsim.utils.BenchmarkTimer
A class to time and manage benchmark results organized in “sections” and “measurements”.
Example
from iactsim.utils import BenchmarkTimer import random import time class Foo(): def __init__(self): self.timer = BenchmarkTimer() self.timer.add_section('foo1') self.timer.add_section('foo2') def foo1(self): t0 = time.time() time.sleep(random.randint(0,50)/1000.) t1 = time.time() time.sleep(random.randint(0,5)/1000.) t2 = time.time() self.timer.add_entry('foo1', 'First', t1-t0) self.timer.add_entry('foo1', 'Second', t2-t1) def foo2(self): t0 = time.time() time.sleep(random.randint(0,30)/1000.) t1 = time.time() self.timer.add_entry('foo2', 'foo2', t1-t0) foo = Foo() for i in range(100): foo.foo1() foo.foo2() foo.timer.print_results()
Methods:
add_entry(section_name, measure_name, ...)Adds a timing entry for a specific measure within a section.
add_section(section_name)Adds a new section (e.g., a method name) to the results.
clear()Resets the timer, keeping sections and measures, but clearing samples.
Returns the raw results dictionary.
print_results([title, show_total, ...])Prints the timings, handling both notebook and console output.
- add_entry(section_name, measure_name, elapsed_time)
Adds a timing entry for a specific measure within a section.
- add_section(section_name)
Adds a new section (e.g., a method name) to the results.
- Parameters:
section_name (str) – The name of the section to add.
- clear()
Resets the timer, keeping sections and measures, but clearing samples.
- get_results()
Returns the raw results dictionary.
- Returns:
The results dictionary, structured as: {section_name: {measure_name: [time1, time2, …]}}
- Return type:
- iactsim.utils.convert_doxygen_to_numpy(cuda_source, function_name)
Converts Doxygen-style documentation within the given source code to NumPy-style docstrings.
- iactsim.utils.get_kernel(module, kernel_name, max_shared_memory_limit=False)
Get kernel wrapper.
- Parameters:
module (cupy.RawModule) – A CuPy rawModule
kernel_name (str) – Name of the kernel to retrieve and wrap.
- Returns:
Wrapper to the RawKernel with a NumPy-style docstring.
- iactsim.utils.wrap_cupy_rawkernel(raw_kernel, docstring)
Generates wrapper function for a CuPy RawKernel. The wrapper allows you to provide a custom docstring.
- Parameters:
raw_kernel (cupy.RawKernel) – The cupy.RawKernel object to wrap.
docstring (str) – A custom docstring for the wrapped kernel.
- Returns:
A Python function that wraps the CuPy RawKernel.
models
models.astri
Classes:
ASTRI Cherenkov camera class. |
|
ASTRI optical system definition (dual-mirror Schwarzschild-Couder). |
|
|
ASTRI telescope. |
- class iactsim.models.astri.AstriCherenkovCamera
ASTRI Cherenkov camera class.
Methods:
acquire_dark_pedestal(n_frame)Acquire pulse-height distribution with an external trigger and the closed lids background.
acquire_pedestal(n_frame)Acquire pulse-height distribution with an external trigger and the current background.
acquire_phd(n_frame[, background, laser_width])Acquire pulse-height distribution with pulsed flash light.
acquire_stairs(start, stop, step[, ...])Acquire staircase curves (pixel dark trigger rate as a function of threshold).
acquire_variance(n_sample_hg[, n_sample_lg, ...])Acquire variance data.
configure(config)Configure the camera with a yaml configuration file or a dictionary.
Optional action that is performed right after the sampling action.
Perform peak detection and pixels trigger time measurement.
threshold_scan(start, stop, step[, ...])Measure the camera trigger rate as a function of the trigger threshold.
Generate a camera trigger.
- acquire_dark_pedestal(n_frame)
Acquire pulse-height distribution with an external trigger and the closed lids background.
- Parameters:
n_frame (int) – number of frame to be acquired.
- acquire_pedestal(n_frame)
Acquire pulse-height distribution with an external trigger and the current background.
- Parameters:
n_frame (int) – number of frame to be acquired.
- acquire_phd(n_frame, background=None, laser_width=10.)
Acquire pulse-height distribution with pulsed flash light.
- acquire_stairs(start, stop, step, integration_time=0.001, window_extent=1024.)
Acquire staircase curves (pixel dark trigger rate as a function of threshold).
- Parameters:
start (float) – Start threshold value.
stop (float) – Stop threshold value.
step (float) – Threshold step.
integration_time (float, optional) – Integration time (in seconds), by default 0.001 s
window_extent (float, optional) – Extent in ns of the time window where to count triggers, by default 1024 ns.
- Returns:
Thresholds and corresponding trigger rate per pixel.
- Return type:
- acquire_variance(n_sample_hg, n_sample_lg=None, source=None, background=None)
Acquire variance data.
- Parameters:
n_sample_hg (int) – Number of HG sample to be acquired.
n_sample_lg (int, optional) – Number of LG sample to be acquired. If None use HG number of sample.
source (int, optional) – Source to be added to the background. If it is not None, the variance is measured at tmin+0.9*(tmax-tmin), where tmin and tmax are the minimum and maximum arrival time of the source. The source arrival times should be uniformly distributed between tmin and tmax. At each variance sample the source arrival times are randomized again, but the number of discharge per pixel/microcell is the same.
background (int, optional) – If not None, temporarly replace the background attribute. The old attribute is restored.
- Returns:
High gain and low gain variance arrays.
- Return type:
tuple(cp.ndarray, cp.ndarray)
Notes
In order to simulate microcells with non-diffused background (e.g. starts), a naive way is to use the output source of the ray-tracing (get_camera_input=True) and randomize the arrival time at each variance sample. This is the default behaviour if you pass source to this method. But remember to generate the source photons with uniform (and large-spreaded) arrival times:
..code-block:: python
source = sources.Source(astri_tel) source.arrival_times.type = ‘uniform’ source.arrival_times.tmin = 0 source.arrival_times.tmax = 2048
Although the timing is handle properly, the microcell IDs are not. A fix for this is planned in the future.
- configure(config)
Configure the camera with a yaml configuration file or a dictionary.
- post_sampling_action()
Optional action that is performed right after the sampling action. This method is called only if a trigger condition is met or if the camera trigger is disabled.
- sampling_action()
Perform peak detection and pixels trigger time measurement.
- threshold_scan(start, stop, step, window_extent=1024., max_duration=1e-3, maximum_count=None, background=None)
Measure the camera trigger rate as a function of the trigger threshold.
- Parameters:
start (float) – Start threshold value.
stop (float) – Stop threshold value.
step (float) – Threshold step.
window_extent (float, optional) – Extent in ns of the time window where to count triggers, by default 1024 ns.
max_duration (float, optional) – Integration time (in seconds) for each threshold, by default 1e-3 s.
maximum_count (int, optional) – Stop when at least
maximum_counttriggers have been found at a each threshold, useful to speed-up the procedure at lower thresholds. By default None.
- Returns:
Thresholds and corresponding rate, rate error and integration time. Integration times can be different for each threshold if a
maximum_countis provided.- Return type:
- trigger_action()
Generate a camera trigger.
- class iactsim.models.astri.AstriOpticalSystem
ASTRI optical system definition (dual-mirror Schwarzschild-Couder).
This class defines the optical geometry and the main shadowing elements of the mechanical structure of the ASTRI telescope.
Coordinate System
Origin (0,0,0): vertex of the primary mirror (M1).
z-axis: optical axis, concave surfaces must have c>0.
Parametrization
The system is divided into independent clusters that can be moved along the optical axis (Z) without affecting other components:
M1: - Static at Z=0. - Can be segmented (hexagonal segments) or monolithic.
Secondary mirror (M2): - Controlled by m2_axial_position. - Includes the M2 mirror and its mechanical baffles.
Camera: - Controlled by fp_axial_position (focal plane vertex); - Includes the focal plane, the camera window, the camera body, and the central tube; - Moving the FP automatically moves the window and sensors;
Direct Surface Access
Apart from the main parameters that control the M1, M2, and Camera clusters, the properties of each specific surface can be modified via direct access (e.g.,
self['M2'].position =).Warning
When modifying surfaces directly, no overlap or collision checks are performed.
When to call rebuild_structure() manually: If you modify a parameter that affects dependent geometry (e.g., changing M2 position should change the M2 Baffle position), you can call self.rebuild_structure() manually after your changes to apply them to the rest of the system.
The auto-reorganization of the surfaces is not completely supported, please check your geometry with visualization.VTKOpticalSystem. A lot of surfaces are destroyed and recreated from scratch whenever rebuild_structure() is called. Any custom properties applied directly will be lost. So, it would be better to assign non-geometry properties after calling rebuild_structure().
See also
Methods:
Builds the 18 hexagonal segments of M1 using nominal coordinates.
configure(config)Configure the optical system.
Full rebuild of all component positions based on current independent parameters.
Removes M1 segments and restores the monolithic M1 mirror.
Removes the window layers and restores the dummy window.
set_camera_window_parameters(radius, ...[, ...])Set the camera window parameters and build the window layers.
Attributes:
Axial position of the camera body center.
Cylindrical camera body dimensions [radius, height].
Dictionary of camera window parameters.
Axial position of the focal plane vertex.
Axial position of the M2 mirror vertex.
- build_m1_segments()
Builds the 18 hexagonal segments of M1 using nominal coordinates. Each segment inherits optical properties from the monolithic M1, which is then removed.
- property camera_body_axial_position
Axial position of the camera body center.
- property camera_body_size
Cylindrical camera body dimensions [radius, height].
- property camera_window_parameters: Dict[str, float] | None
Dictionary of camera window parameters. Read-only property. Use set_camera_window_parameters to modify.
- default_m1_a = array([-0.00000000e+00, -9.61059434e-13, 5.65500725e-20, -6.77984630e-27, -3.89587887e-33, -5.28038180e-40, 2.99106074e-47, 4.39153059e-53, 6.17433202e-60, -2.73586546e-66])
- default_m2_a = array([-0.00000000e+00, -1.62075903e-11, 2.89584356e-17, -8.63371219e-24, -3.34855806e-30, 1.03361002e-36, 6.73525366e-43, 3.06547119e-49, -3.17161236e-55, 3.71183104e-62])
- property fp_axial_position
Axial position of the focal plane vertex. Changing this moves the camera sensitive surface, window, and central tube.
- property m2_axial_position
Axial position of the M2 mirror vertex. Changing this moves M2 and its baffles.
- rebuild_structure()
Full rebuild of all component positions based on current independent parameters.
- remove_m1_segments()
Removes M1 segments and restores the monolithic M1 mirror.
- set_camera_window_parameters(radius, sipm_distance, thickness, separation, top_camera_body_distance, layer_1_as_cylinder=True, layer_2_as_cylinder=True, layer_3_as_cylinder=True)
Set the camera window parameters and build the window layers.
- Parameters:
radius (float) – Radius of the window layers.
sipm_distance (float) – Distance from the SiPM surface to the window.
thickness (float) – Thickness of each window layer.
separation (float) – Separation between window layers.
top_camera_body_distance (float) – Distance between the top window layer and the top of the camera body.
- Return type:
- class iactsim.models.astri.AstriTelescope(optical_system=None, camera=None, position=(0., 0., 0.), pointing=(0, 0))
ASTRI telescope.
Warning
In order to perform camera simulation the optical_system.build_camera_modules() must be called before cuda_init() call. Do not change the number of pixels or the number of modules.
See also
Methods:
configure(config)Configure the telescope with a yaml configuration file or dictionaries. The configuration files can contain more than a document to initialize also the optical system and the Cherenkov camera::.
Helper method to update the number of microcells of each SiPM following the definition in the optical system.
- configure(config)
Configure the telescope with a yaml configuration file or dictionaries. The configuration files can contain more than a document to initialize also the optical system and the Cherenkov camera:
---- # Telescope configuration # ... # ... ---- # Optical system configuration # ... # ... ---- # Camera configuration # ... # ...
- update_camera_ucells()
Helper method to update the number of microcells of each SiPM following the definition in the optical system.
Warning
Changing the number of pixel or the number of modules is not supported.
iactxx
pybind11 extension module for iactsim
Submodule for io operations
Classes:
Class that represents a file produced by CORSIKA IACT extension. |
|
Represents a telescope definition with x, y, z coordinates and reference sphere radius r. |
Functions:
|
Read a file produced by CORSIKA IACT extension and return a |
|
Read in parallel a list of files produced by CORSIKA IACT extension and return the corresponding |
- class iactsim.iactxx.io.IACTFile
Class that represents a file produced by CORSIKA IACT extension.
Usage
filepath = "/path/to/corsika/file" cfile = iactxx.io.IACTFile() # Scan file for memory allocation cfile.set_filepath(filepath) # Decode photon bunches cfile.parse_bunches() # Convert photon bunches units into iactsim default units cfile.convert_bunches()
Note
Only gzip and zstd compressed files are supported. Files written with STORE_EMITTER option are not supported.
See also
read_corsika_file()utility function to read, parse and covert bunches from a file.
read_corsika_files()utility function to read, parse and covert bunches from multiple files in parallel.
Attributes:
Get azimuth offset w.r.t.
Get azimuth range
Get number of photons per bunch
Get energy slope
Get file size (in byte)
Get the the CORSIKA input card
Get maximum simulated photon wavelength
Get minimum simulated photon wavelength
Get maximum energy
Get maximum impact
Get minimum energy
Get total number of events (taking reused into account)
Get number of simulated telescopes
Get particle ID
Get mean pointing direction
Get run ID
Get view cone
Get zenith range
Methods:
convert_bunches(self)Convert photon bunches units
get_event_bunches(self, tel_id, event_index)Returns bunches of an event as a list of NumPy array of photon positions, directions, wavelengths, arrival times, emission altitudes and weights to be passed to
iactsim.IACT.trace_photons()method.get_event_headers(self)Get event header of all simulated events
get_event_number_of_bunches(self, tel_id)Get number of bunches of each event for a given telescope
get_event_particles(self, event_index)Returns particles reaching the observation level for an event as a single NumPy structured array.
get_from_input_card(self, keyword)Get a keyword from the CORSIKA input card
get_number_of_bunches(self)Get number of bunches of all telescopes
get_telescope_bunches(self, tel_id)Returns bunches as a list of NumPy array view of photon positions, directions, wavelengths, arrival times, emission altitudes, weights and event mapping to be passed to
iactsim.IACT.trace_photons()method.get_telescope_definition(self, tel_id)Get telescope definition (unit in mm)
get_telescope_event_headers(self, tel_id)Get event header of all events seen by a telescope (i.e. events with at least min_n_bunches bunches registered at the telescope observation level).
get_telescope_event_ids(self, tel_id)Get identifier of all events seen by a telescope (i.e. events with at least min_n_bunches bunches registered at the telescope observation level).
get_telescope_number_of_bunches(self, tel_id)Get number if bunches hitting the telescope with ID tel_id
parse_bunches(self)Read photon bunches
set_filepath(self, filepath)Link to a file
set_minimum_number_of_bunches(self, n_bunches)Set minimum number of bunches
set_telescopes_to_skip(self, telescopes)Set which telescopes can be skipped
- property azimuth_offset
Get azimuth offset w.r.t. CORSIKA reference system (geomagnetic north)
- property azimuth_range
Get azimuth range
- property bunch_size
Get number of photons per bunch
- convert_bunches(self: iactsim.iactxx.io.IACTFile) None
Convert photon bunches units
- property energy_slope
Get energy slope
- property filesize
Get file size (in byte)
- get_event_bunches(self: iactsim.iactxx.io.IACTFile, tel_id: SupportsInt | SupportsIndex, event_index: SupportsInt | SupportsIndex) list
Returns bunches of an event as a list of NumPy array of photon positions, directions, wavelengths, arrival times, emission altitudes and weights to be passed to
iactsim.IACT.trace_photons()method.For example, if
cfileis aIACTFileinstance andtelescopeaIACTinstance:telescope.trace_photons( *cfile.get_event_bunches(tel_id, event_index), photons_per_bunch=cfile.bunch_size, unpack_wavelength_range=(cfile.lambda_min, cfile.lambda_max), shift_to_z_level=2.*cfile.get_telescope_definition(tel_id).r, simulate_camera=True )
- Parameters:
tel_id (int) – CORSIKA telescope ID
event_index (int) – Index of the event in the list of events seen by the telescope with ID tel_id (i.e. the index of the event in the list returned by
get_telescope_event_headers()method)
Note
Bunches are registered at the telescope observation level, so the they need to be shifted at an higher z-level (e.g. 2 times the telescope reference sphere radius) to correctly perform the ray tracing.
- get_event_headers(self: iactsim.iactxx.io.IACTFile) numpy.typing.NDArray[iactxx::eventio::EventHeader]
Get event header of all simulated events
- get_event_number_of_bunches(self: iactsim.iactxx.io.IACTFile, tel_id: SupportsInt | SupportsIndex) list[int]
Get number of bunches of each event for a given telescope
- get_event_particles(self: iactsim.iactxx.io.IACTFile, event_index: SupportsInt | SupportsIndex) numpy.typing.NDArray[iactxx::eventio::ParticleData]
Returns particles reaching the observation level for an event as a single NumPy structured array.
- Parameters:
event_index (int) – Index of the event.
- get_from_input_card(self: iactsim.iactxx.io.IACTFile, keyword: str) list[float]
Get a keyword from the CORSIKA input card
- get_number_of_bunches(self: iactsim.iactxx.io.IACTFile) dict
Get number of bunches of all telescopes
- get_telescope_bunches(self: iactsim.iactxx.io.IACTFile, tel_id: SupportsInt | SupportsIndex) list
Returns bunches as a list of NumPy array view of photon positions, directions, wavelengths, arrival times, emission altitudes, weights and event mapping to be passed to
iactsim.IACT.trace_photons()method.For example, if
cfileis aIACTFileinstance andtelescopeaIACTinstance:triggered_events = telescope.trace_photons( *cfile.get_telescope_bunches(tel_id), photons_per_bunch=cfile.bunch_size, unpack_wavelength_range=(cfile.lambda_min, cfile.lambda_max), shift_to_z_level=2.*cfile.get_telescope_definition(tel_id).r, simulate_camera=True )
- Parameters:
tel_id (int) – CORSIKA telescope ID
Note
Bunches are registered at the telescope observation level, so the they need to be shifted at an higher z-level (e.g. 2 times the telescope reference sphere radius) to correctly perform the ray tracing.
- get_telescope_definition(self: iactsim.iactxx.io.IACTFile, tel_id: SupportsInt | SupportsIndex) iactsim.iactxx.io.TelescopeDefinition
Get telescope definition (unit in mm)
- get_telescope_event_headers(self: iactsim.iactxx.io.IACTFile, tel_id: SupportsInt | SupportsIndex) numpy.typing.NDArray[iactxx::eventio::EventHeader]
Get event header of all events seen by a telescope (i.e. events with at least min_n_bunches bunches registered at the telescope observation level)
- get_telescope_event_ids(self: iactsim.iactxx.io.IACTFile, tel_id: SupportsInt | SupportsIndex) numpy.typing.NDArray[numpy.uint64]
Get identifier of all events seen by a telescope (i.e. events with at least min_n_bunches bunches registered at the telescope observation level)
- get_telescope_number_of_bunches(self: iactsim.iactxx.io.IACTFile, tel_id: SupportsInt | SupportsIndex) int
Get number if bunches hitting the telescope with ID tel_id
- property input_card
Get the the CORSIKA input card
- property lambda_max
Get maximum simulated photon wavelength
- property lambda_min
Get minimum simulated photon wavelength
- property max_energy
Get maximum energy
- property maximum_impact
Get maximum impact
- property min_energy
Get minimum energy
- property number_of_events
Get total number of events (taking reused into account)
- property number_of_telescopes
Get number of simulated telescopes
- parse_bunches(self: iactsim.iactxx.io.IACTFile) None
Read photon bunches
- property particle_id
Get particle ID
- property pointing
Get mean pointing direction
- property run_id
Get run ID
- set_filepath(self: iactsim.iactxx.io.IACTFile, filepath: str) None
Link to a file
- set_minimum_number_of_bunches(self: iactsim.iactxx.io.IACTFile, n_bunches: SupportsInt | SupportsIndex) None
Set minimum number of bunches
- set_telescopes_to_skip(self: iactsim.iactxx.io.IACTFile, telescopes: collections.abc.Sequence[SupportsInt | SupportsIndex]) None
Set which telescopes can be skipped
- property view_cone
Get view cone
- property zenith_range
Get zenith range
- class iactsim.iactxx.io.TelescopeDefinition
Represents a telescope definition with x, y, z coordinates and reference sphere radius r.
Attributes:
Radius
X coordinate
Y coordinate
Z coordinate
- property r
Radius
- property x
X coordinate
- property y
Y coordinate
- property z
Z coordinate
- iactsim.iactxx.io.read_corsika_file(filepath: os.PathLike | str | bytes, skip_telescopes: collections.abc.Sequence[SupportsInt | SupportsIndex] = [], min_n_bunches: SupportsInt | SupportsIndex = 0) iactsim.iactxx.io.IACTFile
Read a file produced by CORSIKA IACT extension and return a
IACTFileinstance containing the photon bunches data ready to be passed toiactsim.IACT.trace_photons().
- iactsim.iactxx.io.read_corsika_files(filepaths: collections.abc.Sequence[os.PathLike | str | bytes], skip_telescopes: collections.abc.Sequence[SupportsInt | SupportsIndex] = [], min_n_bunches: SupportsInt | SupportsIndex = 0) list[iactsim.iactxx.io.IACTFile]
Read in parallel a list of files produced by CORSIKA IACT extension and return the corresponding
IACTFileinstances containing the photon bunches data ready to be passed toiactsim.IACT.trace_photons().Useful when multiple compressed CORSIKA files have to be read.
- Parameters:
- Returns:
List of file handlers
- Return type:
list[
IACTFile]
Notes
Parallel reading from HDDs can deteriorate performance.