iactrace.camera¶
The Camera class and detector-side components.
Camera Class¶
- class iactrace.camera.Camera[source]¶
Bases:
ModuleCamera for photon collection and imaging.
The Camera works in its local coordinate system. Sensor positions and rotations are relative to the camera origin (typically [0, 0, 0] for a single-sensor camera). The Telescope transforms the RayBundle into the camera frame before passing it here.
Pipeline:
rb = telescope.render(...) # LazyRayBundle camera.image(rb) # pixel image (fused, per-element fold) camera.response_matrix(rb) # per-source pixel response (fused) camera.collect(rb) # (pe_vals, pe_times, pix_id, detected) camera.trace(rb) # TraceResult through the camera (diagnostics) rb.materialise() # flat camera-frame RayBundle
- Attributes:
- sensor_groups: List of SensorGroup objects. Each group owns its pixel
layout and its detection chain (optional concentrator +
gap+ photodetector), so different groups can carry different cones or photodetectors. Configure a group’s chain when constructing it, or viaset_concentrator()/set_photodetector()/set_gap().
- sensor_groups = <dataclasses._MISSING_TYPE object>¶
- collect(ray_bundle, sensor_idx=0)[source]¶
Per-ray output
(pe_vals, pe_times, pix_id, detected).detectedis the final liveness flag: the chain output’salive(stayed alive through the optics, hit a sensor tile, landed on the photodetector surface) AND-ed with the pixel mask (inside a real pixel, outside the edge deadband). It isFalsefor a ray lost anywhere along the way. Entries ofpix_id/pe_timesfor undetected rays are meaningless and must be filtered with this mask before use;pe_valsis already zeroed there.Materialises a
LazyRayBundle: per-ray output cannot be produced incrementally.For the path rays took through the camera, see
trace().
- trace(ray_bundle, sensor_idx=0)[source]¶
The path rays take through the camera, for diagnostics / visualization.
Returns a
TraceResult, like every other tracer. This one always records, so itstrajectoryis neverNone: a camera-frameTrajectoryrunning from the last optic, through each ray’s landing on its pixel, to the end of the detection chain – the final converging leg and the scattering inside the concentrator as one continuous path.raysis the bundle the detection chain produced, ascollect()reports it.The viz helpers take the result as-is (
show_camera(camera, trajectory=camera.trace(rb))); reach for.trajectorywhen you want the path itself.
- image(ray_bundle, sensor_idx=0)[source]¶
Pixel image of shape
(n_sensors, *pixel_shape).Accepts either a flat
RayBundle(e.g. fromTelescope.trace()) or theLazyRayBundlereturned byTelescope.render(). The lazy form folds per primary-mirror element so the full ray buffer is never materialised; the eager form scatters the buffer in one call.For the path rays took through the camera, see
trace().
- response_matrix(lazy_bundle, sensor_idx=0)[source]¶
Per-source pixel response, shape
(n_sources, n_sensors, *pixel_shape).Folds per stage-0 element instead of materialising the full ray buffer; peak memory is bounded by the matrix itself.
Requires a
LazyRayBundleso the per-source structure is known. Passtelescope.render(...)directly.
- set_concentrator(sensor_idx, concentrator)[source]¶
Set/replace the concentrator on sensor group
sensor_idx’s chain.
- set_photodetector(sensor_idx, photodetector)[source]¶
Set/replace the photodetector on sensor group
sensor_idx’s chain.
- set_gap(sensor_idx, gap)[source]¶
Set the gap (upstream exit -> detector spacing) on a group’s chain.
- get_info()[source]¶
Summary of the camera configuration.
Each sensor group reports its own geometry and detection chain, since the chain (concentrator + gap + photodetector) is owned per group.
- classmethod from_yaml(filename)[source]¶
Load a Camera from a standalone camera YAML file.
Sensor positions are interpreted as camera-local coordinates.
- Args:
filename: Path to camera YAML file.
- Returns:
Camera object.
- to_yaml(filename, precision=6, overwrite=True)[source]¶
Save camera to a standalone YAML file.
Sensor positions are written in camera-local coordinates.
- Args:
filename: Output file path. precision: Number of decimal places for float values. overwrite: If True, overwrite existing file.
- Returns:
Path to the saved file.
Sensor Groups¶
Sensors live in the camera-local frame and accumulate rays into pixels.
- class iactrace.camera.SensorGroup[source]¶
Bases:
ModuleAbstract base class for sensor groups.
A sensor group contains N sensors at different positions/orientations that share the same pixel geometry and the same detection chain. Each group owns its
DetectionChain(optional concentrator + gap + photodetector), so distinct groups in oneCameracan carry different cones or photodetectors.- Attributes:
positions: Sensor positions in 3D space (N, 3) rotations: Sensor rotations as Euler angles in degrees (N, 3) chain: The per-pixel
DetectionChainapplied to every pixel of this group.
- positions = <dataclasses._MISSING_TYPE object>¶
- rotations = <dataclasses._MISSING_TYPE object>¶
- chain = <dataclasses._MISSING_TYPE object>¶
- property n_sensors¶
Return number of sensors in the group.
- abstractmethod get_accumulator_shape()[source]¶
Return the shape of the accumulator array per sensor.
- abstractmethod pixel_index_and_mask(sensor_idx, x, y)[source]¶
Localize
(x, y)to a flat pixel index plus a validity mask.
- property pixel_frame_rotation¶
- scatter(pix_id, valid, values)[source]¶
Sum values into the pixel accumulator by precomputed assignment.
- abstractmethod in_bounds(x, y)[source]¶
Predicate: True for
(x, y)inside the sensor’s active footprint.
- with_concentrator(concentrator)[source]¶
Return a copy of this group with its chain’s concentrator replaced.
- with_photodetector(photodetector)[source]¶
Return a copy of this group with its chain’s photodetector replaced.
- abstractmethod to_pixel_frame(sensor_rays, pix_id)[source]¶
Re-express tile-local rays in their assigned pixel’s local frame.
- abstractmethod from_pixel_frame(points, pix_id)[source]¶
Map pixel-local points back to the tile-local frame.
The inverse of
to_pixel_frame()for positions, undoing the pixel centre offset (and any grid alignment) for each ray’s assigned pixel.pointsis(..., n_rays, 3)andpix_id(n_rays,), so a whole recorded trajectory can be lifted out of the pixel frame in one call – which is what turns a chain trace into something drawable alongside the rest of the camera.
- __init__(positions, rotations, chain)¶
- class iactrace.camera.SquareSensorGroup[source]¶
Bases:
SensorGroupSquare pixel sensor group.
- __init__(positions, rotations, width, height, bounds, edge_width=0.0, concentrator=None, photodetector=None, gap=0.0)[source]¶
Square-pixel sensor group.
- Args:
positions: Sensor positions, shape
(N, 3)(or(3,)for one). rotations: Euler angles in degrees, same shape aspositions. width: Pixel count along x (> 0). height: Pixel count along y (> 0). bounds:(x_min, x_max, y_min, y_max)in the sensor-local frame. edge_width: Dead-zone width at pixel edges (>= 0). concentrator: Optional per-pixel light concentrator (e.g. a- photodetector: Per-pixel detector response.
Nonedefaults to a perfect flat
ConstantQE.- gap: Spacing from the concentrator exit (or the entrance plane when
there is no concentrator) to the detector (
>= 0).
- photodetector: Per-pixel detector response.
- Raises:
- ValueError: on malformed shapes, non-positive
width/height, degenerate
bounds, or negativeedge_width.
- ValueError: on malformed shapes, non-positive
- positions = <dataclasses._MISSING_TYPE object>¶
- rotations = <dataclasses._MISSING_TYPE object>¶
- width = <dataclasses._MISSING_TYPE object>¶
- height = <dataclasses._MISSING_TYPE object>¶
- edge_width = <dataclasses._MISSING_TYPE object>¶
- x0 = <dataclasses._MISSING_TYPE object>¶
- y0 = <dataclasses._MISSING_TYPE object>¶
- dx = <dataclasses._MISSING_TYPE object>¶
- dy = <dataclasses._MISSING_TYPE object>¶
- property bounds¶
Return (x_min, x_max, y_min, y_max) pixel bounds.
- pixel_index_and_mask(sensor_idx, x, y)[source]¶
Localize
(x, y)to a flat pixel index plus a validity mask.
- to_pixel_frame(sensor_rays, pix_id)[source]¶
Re-express tile-local rays in their assigned pixel’s local frame.
- from_pixel_frame(points, pix_id)[source]¶
Map pixel-local points back to the tile-local frame.
The inverse of
to_pixel_frame()for positions, undoing the pixel centre offset (and any grid alignment) for each ray’s assigned pixel.pointsis(..., n_rays, 3)andpix_id(n_rays,), so a whole recorded trajectory can be lifted out of the pixel frame in one call – which is what turns a chain trace into something drawable alongside the rest of the camera.
- class iactrace.camera.HexagonalSensorGroup[source]¶
Bases:
SensorGroupHexagonal pixel sensor group.
- __init__(positions, rotations, hex_centers, edge_width=0.0, concentrator=None, photodetector=None, gap=0.0)[source]¶
Hexagonal-pixel sensor group.
- Args:
positions: Sensor positions, shape
(N, 3)(or(3,)for one). rotations: Euler angles in degrees, same shape aspositions. hex_centers: Pixel centres, shape(M, 2). The grid geometry(size, rotation, offset, lookup table) is auto-detected from these on construction.
edge_width: Dead-zone width at pixel edges (
>= 0). concentrator: Optional per-pixel light concentrator (e.g. a- photodetector: Per-pixel detector response.
Nonedefaults to a perfect flat
ConstantQE.- gap: Spacing from the concentrator exit (or the entrance plane when
there is no concentrator) to the detector (
>= 0).
- photodetector: Per-pixel detector response.
- Raises:
- ValueError: on malformed shapes, empty
hex_centers, or negative edge_width.
- ValueError: on malformed shapes, empty
- positions = <dataclasses._MISSING_TYPE object>¶
- rotations = <dataclasses._MISSING_TYPE object>¶
- hex_centers = <dataclasses._MISSING_TYPE object>¶
- n_pixels = <dataclasses._MISSING_TYPE object>¶
- edge_width = <dataclasses._MISSING_TYPE object>¶
- hex_size = <dataclasses._MISSING_TYPE object>¶
- hex_inradius = <dataclasses._MISSING_TYPE object>¶
- grid_rotation = <dataclasses._MISSING_TYPE object>¶
- grid_offset = <dataclasses._MISSING_TYPE object>¶
- lookup_table = <dataclasses._MISSING_TYPE object>¶
- q_min = <dataclasses._MISSING_TYPE object>¶
- r_min = <dataclasses._MISSING_TYPE object>¶
- pixel_centers_grid = <dataclasses._MISSING_TYPE object>¶
- property pixel_frame_rotation¶
The detected grid rotation – see
SensorGroup.pixel_frame_rotation.
- pixel_index_and_mask(sensor_idx, x, y)[source]¶
Localize
(x, y)to a flat pixel index plus a validity mask.
- to_pixel_frame(sensor_rays, pix_id)[source]¶
Re-express tile-local rays in their assigned pixel’s local frame.
- from_pixel_frame(points, pix_id)[source]¶
Map pixel-local points back to the tile-local frame.
The inverse of
to_pixel_frame()for positions, undoing the pixel centre offset (and any grid alignment) for each ray’s assigned pixel.pointsis(..., n_rays, 3)andpix_id(n_rays,), so a whole recorded trajectory can be lifted out of the pixel frame in one call – which is what turns a chain trace into something drawable alongside the rest of the camera.
Detection chain¶
Each SensorGroup owns a DetectionChain:
an optional concentrator, a gap, and a photodetector, applied to every
pixel of that group. Distinct groups in one camera can therefore carry
different cones or photodetectors. Configure a group’s chain at construction
(concentrator / photodetector / gap arguments) or functionally via
the sensor_idx-keyed Camera.set_concentrator(),
Camera.set_photodetector(), and Camera.set_gap() (documented on
Camera above).
A ray reaching a pixel is traced onto the photodetector’s
DetectionSurface (its photocathode
geometry) and then weighted by the photodetector’s response.
- class iactrace.camera.DetectionChain[source]¶
Bases:
ModuleA pixel’s detection train: (optional concentrator) -> surface -> photodetector.
Every chain traces rays up to the photodetector’s own sensor surface (its photocathode geometry,
surface) and hands the resulting bundle back to the photodetector, which applies its detection efficiencies (QE, window response, …). Geometry is owned by the photodetector; the chain only places it, at the detector planedetector_zset by the concentrator +gap. The chain is identical for every pixel in a SensorGroup, so it runs once over all rays at once.- Attributes:
concentrator: Optional light concentrator (cone / lightguide). photodetector: Photodetector – both the response and (via its
surface) the photocathode geometry rays are traced to.- gap: Spacing from the concentrator exit (or the entrance with no cone) to
the detector plane where the photocathode is mounted. Defaults
0.0.
- concentrator = <dataclasses._MISSING_TYPE object>¶
- photodetector = <dataclasses._MISSING_TYPE object>¶
- gap = 0.0¶
- with_concentrator(concentrator)[source]¶
Return a copy of this chain with its concentrator replaced.
- with_photodetector(photodetector)[source]¶
Return a copy of this chain with its photodetector replaced.
- property detector_z¶
-(length + gap).- Type:
Detector-plane position in the pixel-local frame
- property surface¶
The photodetector’s sensor surface, placed at
detector_z.The photodetector owns the surface with
vertex_zrelative to the detector plane; this property shifts it into absolute pixel-local coordinates – the surface rays are actually traced onto. Public so diagnostics (e.g.iactrace.viz.show_sensor_chain()) can read the placed geometry.
- propagate(local_rays, record_trajectory=False)[source]¶
Trace local_rays to the sensor surface, then hand off to the photodetector.
local_raysare in the pixel-local frame (entrance atz = 0). With a concentrator, they are delivered tosurfaceby the concentrator’s ownto_surface(). With no concentrator the rays advance straight onto the surface. The handover to the photodetector is just the resulting bundle – rays at the surface, pixel-local frame – which it weights by its own detection efficiency (reading any geometry it needs from the surface it owns). Optical path length is accumulated up to the surface (concentrator fill index on its internal leg, ray mediumnon the free legs).Returns a
TraceResult; take itsraysfor the detected bundle. Passrecord_trajectory=Trueto also populate itstrajectorywith the path through the chain (pixel-local frame): the wall-by-wall bounce path where the concentrator can report one, otherwise the straight entrance-to-landing segment. Off by default, andtrajectoryis thenNone.
- __init__(concentrator, photodetector, gap=0.0)¶
- class iactrace.camera.detector.surface.DetectionSurface[source]¶
Bases:
ModuleThe sensor surface a detection chain delivers rays onto.
- Args:
- shape: Optional single-element core surface group giving the sag
z(x, y)in the vertex frame (element0is used). Mutually exclusive withcurvature/conic.- vertex_z: Axial position of the surface vertex, relative to the
detector plane (
0= at the plane).- curvature:
c = 1 / R.0-> flat.> 0concave toward the incoming light (bowl);
< 0convex (a dome bulging toward +z).
conic: Conic constant
k(0-> sphere). radius: Aperture radius; rays landing beyond it are dropped.None-> unbounded.
- Raises:
- ValueError: on non-positive
radius, or when bothshapeand curvature/conicare given.
- ValueError: on non-positive
- vertex_z = <dataclasses._MISSING_TYPE object>¶
- radius = <dataclasses._MISSING_TYPE object>¶
- is_flat = <dataclasses._MISSING_TYPE object>¶
- shape = <dataclasses._MISSING_TYPE object>¶
- sag_fn()[source]¶
Return this surface’s
z(x, y)sag function.For callers (e.g. 3D visualisation) that need a plain sag callable rather than the full intersection machinery.
Concentrators¶
Optional light concentrators (e.g. Winston cones) sit between the incoming
rays and the photodetector. Optical path length through the guide is weighted
by the concentrator’s fill index (1.0 for an air-filled cone). All cones
share the PolygonalCone wall-tracing base.
- class iactrace.camera.Concentrator[source]¶
Bases:
ModuleAbstract base for per-pixel light concentrators.
A concentrator funnels light from its entrance aperture (
z = 0) toward its exit aperture (z = -length) in its local space, onto a stopping surface. Its one transport primitive isto_surface(): deliver rays from the entrance aperture onto a givenDetectionSurface, tracing the concentrator’s own internal geometry jointly with that surface.- length = <dataclasses._MISSING_TYPE object>¶
- abstractmethod to_surface(rays, surface)[source]¶
Deliver rays from the entrance aperture onto surface.
- Args:
rays: Rays at the entrance aperture, pixel-local frame. surface: The stopping surface, placed in the pixel-local frame.
- Returns:
Rays landed on surface, same frame.
- trace_to_surface(rays, surface)[source]¶
to_surface(), additionally reporting the path rays took.Returns a
TraceResultwhosetrajectoryruns through the pixel-local frame, or isNonewhen this concentrator cannot report a path – the base implementation, which subclasses that trace internally (e.g.PolygonalCone) override. Callers fall back to a straight entrance-to-landing segment onNone.
- apply(rays)[source]¶
Transport rays to the exit aperture (a flat plane at
z = -length).Convenience for standalone concentrator use / diagnostics:
to_surface()onto a flat, unbounded stop at the exit aperture.
- cross_sections()[source]¶
Optional geometry for
iactrace.viz.show_sensor_chain().Returns
(z, rings)orNone:z; shape(K,)axial samples,z[0] = 0(entrance) ..z[-1] = -length(exit).rings; shape(K, M, 2): theM-gon wall cross-section at each slice in the pixel-local frame (M = 6hex,M = 4square, largeM~ round).rings[0]is the entrance aperture,rings[-1]the exit aperture.
The default returns
None(“not drawable”); concrete concentrators override it once they know their profile.
- __init__(length)¶
- class iactrace.camera.PolygonalCone[source]¶
Bases:
ConcentratorA hollow reflective cone whose
n_sidesfacets are lofted around a meridian: one concreteConcentratorthat delivers rays by bouncing them off its reflecting walls.Geometry. The facet plane normals (
n_hats) and the drawable cross-sections depend only on the polygon (n_sides,orientation) and on the meridian samples the subclass provides via_meridian().Wall tracing.
to_surface()runs the sharedtrace_chain()bounce loop, which asks the cone for the raw nearest wall hit (_nearest_hit()); the cavity clamp (nearest_hit()), the mouth-aperture mask (in_mouth()) and the off-wall reflection book-keeping (reflect_ray()) are shared here. All tracer coordinates are the cone frame (exitz = 0, mouthz = length).
A new cone type therefore only describes its meridian profile (
_meridian()) and its per-facet intersection (_nearest_hit()). Every field is static, so the whole cone is a leaf-free pytree the tracer can broadcast throughvmapat no runtime cost.- n_sides = <dataclasses._MISSING_TYPE object>¶
- orientation = <dataclasses._MISSING_TYPE object>¶
- entrance_apothem = <dataclasses._MISSING_TYPE object>¶
- exit_apothem = <dataclasses._MISSING_TYPE object>¶
- reflectivity = <dataclasses._MISSING_TYPE object>¶
- max_bounces = <dataclasses._MISSING_TYPE object>¶
- property n_hats¶
(M, 2) inward plane normals of the polygon facets.
- nearest_hit(o, d)[source]¶
Nearest forward wall hit for one ray, clamped to
z in [0, length].Returns
(t, normal)witht = infwhen the nearest wall root falls outside the cavity – e.g. the ray has dropped below the exit, where the infinite wall surface would otherwise give a spurious root.
- reflect_ray(o, d, t, normal)[source]¶
Reflect one ray off a wall hit at parameter
t.Returns
(new_origin, new_direction, path_added). The new origin is nudged just off the wall along the reflected ray so the next intersection test sees this wall behind it; the nudge lies on the outgoing ray, so it is added back to the optical path and the geometry stays exact.
- to_surface(rays, surface)[source]¶
Trace rays through the reflecting walls onto surface.
The wall-based implementation of
to_surface(): the sharedtrace_chain()bounces rays off the cavity walls and lands them on surface, co-traced so a sensor surface peeking into the cavity is hit mid-bounce.
- trace_to_surface(rays, surface)[source]¶
to_surface(), also returning the per-bounce wall path.
- cross_sections()[source]¶
Optional geometry for
iactrace.viz.show_sensor_chain().Returns
(z, rings)orNone:z; shape(K,)axial samples,z[0] = 0(entrance) ..z[-1] = -length(exit).rings; shape(K, M, 2): theM-gon wall cross-section at each slice in the pixel-local frame (M = 6hex,M = 4square, largeM~ round).rings[0]is the entrance aperture,rings[-1]the exit aperture.
The default returns
None(“not drawable”); concrete concentrators override it once they know their profile.
- __init__(length, n_sides, orientation, entrance_apothem, exit_apothem, reflectivity, max_bounces)¶
- class iactrace.camera.WinstonCone[source]¶
Bases:
PolygonalConePolygonal CPC (Winston cone) light guide.
Defined entirely by its physical dimensions; exit apothem, entrance apothem and length. The parabolic-wall tilt
(s, c)that fixes the cone is computed from them at construction (seecpc_wall_tilt()). The cone answers the per-facet meridian-parabola hit (_nearest_hit()); the bounce loop is owned by the sharedtrace_chain().- Args:
n_sides: Number of facets (6 = hexagonal, 4 = square, …). entrance_apothem: Entrance inradius
a1; the apothem **at the entranceplane**
z = length. For a truncated cone this is the actual (truncated) entry.exit_apothem: Exit aperture inradius
a2. length: Physical depth.Nonebuilds the full (untruncated) CPC andderives the length from
a1/a2; a value truncates the cone (thenentrance_apothemis the entry at that depth).reflectivity: Per-bounce wall reflectivity (scalar). max_bounces: Maximum reflections traced before a ray is absorbed. orientation_deg: Rotation of the polygon about the optical axis.
- __init__(n_sides, entrance_apothem, exit_apothem, length=None, reflectivity=0.9, max_bounces=10, orientation_deg=0.0)[source]¶
- n_sides = <dataclasses._MISSING_TYPE object>¶
- exit_apothem = <dataclasses._MISSING_TYPE object>¶
- entrance_apothem = <dataclasses._MISSING_TYPE object>¶
- reflectivity = <dataclasses._MISSING_TYPE object>¶
- max_bounces = <dataclasses._MISSING_TYPE object>¶
- orientation = <dataclasses._MISSING_TYPE object>¶
- length = <dataclasses._MISSING_TYPE object>¶
- s = <dataclasses._MISSING_TYPE object>¶
- c = <dataclasses._MISSING_TYPE object>¶
- property k¶
Meridian offset
a2 * (2 + s)of the wall parabola.
- class iactrace.camera.OkumuraCone[source]¶
Bases:
PolygonalConeOkumura light collector: a polygonal cone with Bezier-curve walls.
A hollow light guide whose
n_sideswalls follow a quadratic or cubic Bezier meridian (Okumura 2012, arXiv:1205.3968) rather than the Winston paraboloid. Construct it either from an explicit list of interior control points or viaquadratic()/cubic(), using the relative coordinates tabulated in the paper. Like the Winston cone, it answers the per-facet Bezier-meridian hit (_nearest_hit()); the bounce loop is owned by the sharedtrace_chain().The control points are given in the paper’s normalized box: the exit rim is
(0, 0)and the mouth is(1, 1), so a control point(r, z)hasrinterpolating the inradius fromexit_apothemtoentrance_apothemandzinterpolating the axial position from the exit plane to the mouth.- Args:
n_sides: Number of facets (6 = hexagonal, 4 = square, …). entrance_apothem: Mouth inradius
a1(the apothem atz = length). exit_apothem: Exit aperture inradiusa2. control_points: Interior Bezier control points in normalizedcoordinates –
[(P1r, P1z)]for a quadratic curve,[(P1r, P1z), (P2r, P2z)]for a cubic one. The endpoints(0, 0)(exit) and(1, 1)(mouth) are implied.- length: Physical depth.
Nonedefaults to the length of the equivalent full Winston cone,
L = (a1 + a2) * cos/sin(theta_max)withsin(theta_max) = a2 / a1– the sameLOkumura compares against, so the Okumura cone is a true drop-in for that Winston cone.
reflectivity: Per-bounce wall reflectivity (scalar). max_bounces: Maximum reflections traced before a ray is absorbed. orientation_deg: Rotation of the polygon about the optical axis.
- length: Physical depth.
- Raises:
- ValueError: if
0 < exit_apothem < entrance_apothemis violated, if no interior control point is given, or if the control points give a non-monotonic axial profile
Z(t)(an ill-defined depth).
- ValueError: if
- __init__(n_sides, entrance_apothem, exit_apothem, control_points, length=None, reflectivity=0.9, max_bounces=10, orientation_deg=0.0)[source]¶
- n_sides = <dataclasses._MISSING_TYPE object>¶
- exit_apothem = <dataclasses._MISSING_TYPE object>¶
- entrance_apothem = <dataclasses._MISSING_TYPE object>¶
- length = <dataclasses._MISSING_TYPE object>¶
- control_points = <dataclasses._MISSING_TYPE object>¶
- r_coeffs = <dataclasses._MISSING_TYPE object>¶
- z_coeffs = <dataclasses._MISSING_TYPE object>¶
- reflectivity = <dataclasses._MISSING_TYPE object>¶
- max_bounces = <dataclasses._MISSING_TYPE object>¶
- orientation = <dataclasses._MISSING_TYPE object>¶
- classmethod quadratic(n_sides, entrance_apothem, exit_apothem, p1, **kwargs)[source]¶
Build a quadratic Okumura cone from its single Bezier control point
P1.
- classmethod cubic(n_sides, entrance_apothem, exit_apothem, p1, p2, **kwargs)[source]¶
Build a cubic Okumura cone from its Bezier control points
P1andP2.
- property degree¶
Degree of the Bezier meridian (2 = quadratic, 3 = cubic).
Photodetectors¶
A photodetector is the terminal element of a detection chain: it owns its sensor surface and weights each landed ray by its detection efficiency.
- class iactrace.camera.PhotoDetector[source]¶
Bases:
ModuleAbstract base for photodetector response models.
A photodetector is the terminal element of a detection chain and owns two things:
Its surface (
surface): theDetectionSurfacethe chain traces rays onto – by definition every photodetector has one. The base class provides the default (an unbounded flat detector at the chain’s detector plane); photodetectors with a curved / apertured photocathode override the property.Its response (
detect()): it receives the rays the chain has delivered onto that surface and weightsvaluesby its detection efficiency. The handover is just theRayBundle; a photodetector with an angle-dependent response reads the geometry it needs from its own surface (e.g.normals_at()at the landing positions, turned into incidence cosines withincidence_cos()).
- property surface¶
The sensor surface, with
vertex_zrelative to the detector plane.
- abstractmethod detect(local_rays)[source]¶
Weight local_rays by detection efficiency at the sensor surface.
- Args:
- local_rays: Rays landed on the surface, pixel-local frame (true
directions preserved; dead / undetected rays carry
0).
- Returns:
Rays with photoelectron-weighted
values; geometry unchanged.
- outline()[source]¶
Optional active-area polygon
(M, 2)for the diagnostic viz.Expressed in the pixel-local frame. The default returns
None(“not drawable”), in which caseiactrace.viz.show_sensor_chain()falls back to the entrance-aperture footprint.
- envelope()[source]¶
Optional 3D envelope
(z, rings)foriactrace.viz.show_sensor_chain().Mirrors
cross_sections()for the detector side: a surface of revolution / lofted wall drawn around the detector plane so a physical photodetector body (e.g. a PMT’s glass front + tube) becomes visible.z; shape(K,)axial samples in the pixel-local frame, withz = 0at the photocathode (detector) plane and+ztoward the incoming light. The viz offsets these todetector_z.rings; shape(K, M, 2)wall cross-section at each slice (largeM~ round).
The default returns
None(“no envelope drawn”); photodetectors with a physical body override it.
- __init__()¶
- class iactrace.camera.ConstantQE[source]¶
Bases:
PhotoDetectorFlat scalar quantum efficiency with no spatial or angular structure.
The simplest photodetector and the default detector response: a single efficiency
qeapplied uniformly to every ray reaching the surface (the inherited flat detector at the chain’s detector plane). Use it for a measured detection efficiency you want applied as a plain scalar, or as a perfect (qe = 1) pass-through.- Args:
qe: Quantum efficiency in
[0, 1].
- qe = <dataclasses._MISSING_TYPE object>¶
- class iactrace.camera.PMT[source]¶
Bases:
PhotoDetectorA photomultiplier: a sensor surface + a cylindrical body.
A self-contained photodetector bundling everything a PMT contributes to detection, applied after the chain hands rays over to the sensor surface:
Geometry. The sensor surface is the sensor surface the chain traces rays onto (
surface): bounded byface_radiusand placed with its vertex atvertex_z(relative to the detector plane;0= flush with the mount,> 0peeks toward the light, as for a domed window).Efficiency. A single detection efficiency
qeis applied to every ray landing on the sensor surface. Real PMT efficiencies are measured with the entrance glass in place, soqeis the whole measured number and needs no separate window term – this is the default (n_window = None).Optional entrance window. Set
n_windowto also weight each ray by the unpolarized Fresnel transmittance at the air/window interface for its incident angle – the angular response a single measured scalar cannot capture. When you do,qeshould be the intrinsic photocathode QE (the glass loss is then modelled by the Fresnel term, not folded intoqe).
A
FreeformSurfaceGroupsensor is supported at the Python level (pass it assurface), but – like a freeform mirror or lens surface – is not representable in YAML.- Args:
- qe: Detection efficiency in
[0, 1]applied at the photocathode. Defaults to
1.0.- n_window: Refractive index of the entrance window.
None(default) applies
qealone. A value> 1(e.g.1.48for borosilicate glass) additionally weights each ray by the incident-angle Fresnel transmittance through the window.
face_radius: Sensor surface aperture radius (and the body radius). surface: The sensor surface figure, a single-element
SurfaceGroup(typically anAsphericSurfaceGroup, optionally summed with aZernikeSurfaceGroupviaSumSurfaceGroup).None(default) is a flat window.- vertex_z: Axial position of the surface’s vertex, relative to the
detector plane (
0= at the plane; same convention asvertex_z).- length: Axial length of the cylindrical body behind the sensor surface.
Nonedefaults to2 * face_radius.
n_facets: Facets of the revolved body (
48~ round).- qe: Detection efficiency in
- Raises:
- ValueError: on
qeoutside[0, 1],n_window <= 1, non-positive face_radius, negativelength, orn_facets < 3.
- ValueError: on
- __init__(qe=1.0, *, n_window=None, face_radius, surface=None, vertex_z=0.0, length=None, n_facets=48)[source]¶
- qe = <dataclasses._MISSING_TYPE object>¶
- n_window = <dataclasses._MISSING_TYPE object>¶
- face_radius = <dataclasses._MISSING_TYPE object>¶
- shape = <dataclasses._MISSING_TYPE object>¶
- vertex_z = <dataclasses._MISSING_TYPE object>¶
- length = <dataclasses._MISSING_TYPE object>¶
- n_facets = <dataclasses._MISSING_TYPE object>¶
- detect(local_rays)[source]¶
Weight local_rays by detection efficiency at the sensor surface.
- Args:
- local_rays: Rays landed on the surface, pixel-local frame (true
directions preserved; dead / undetected rays carry
0).
- Returns:
Rays with photoelectron-weighted
values; geometry unchanged.
- property surface¶
The sensor surface.
shapesupplies the figure (flat by default; curved / aspheric / Zernike otherwise), placed with its vertex atvertex_zand bounded byface_radius– the exact sameDetectionSurfacemachinery used by every other photodetector’s surface.
- outline()[source]¶
Optional active-area polygon
(M, 2)for the diagnostic viz.Expressed in the pixel-local frame. The default returns
None(“not drawable”), in which caseiactrace.viz.show_sensor_chain()falls back to the entrance-aperture footprint.
- envelope()[source]¶
Body-only cylinder for the viz:
vertex_z->vertex_z - length.The entry window is the sensor surface, drawn separately; the body is just the tube behind it, sharing the rim circle (
z = vertex_z,r = face_radius) with a flat / recessed sensor surface so the two fit without intersection. A sensor surface that bulges past its rim (a strongly domedshape) is drawn with its body starting at the mount rather than the true apex; this is a diagnostic-viz simplification only, not a tracing concern.