Metadata-Version: 2.4
Name: rayd-torch
Version: 0.8.0
Summary: Torch-native RayD geometry and multipath primitives.
Author-Email: Xingyu Chen <xic063@ucsd.edu>
License-Expression: BSD-3-Clause
Requires-Python: <3.15,>=3.10
Requires-Dist: torch<2.11,>=2.10
Description-Content-Type: text/markdown

# RayD Torch

RayD Torch is a Torch-native CUDA/OptiX package for RayD geometry primitives and
RayD-style multipath/diffraction kernels.

```python
import rayd.torch as rt
```

Install the `rayd-torch` distribution. It owns only `rayd/torch/**` and can
coexist with the independently installed `rayd-drjit` backend.

Published complete wheels are built for and require PyTorch 2.10
(`torch>=2.10,<2.11`) because `_legacy_ops` uses the non-Stable-ABI
LibTorch C++ surface. The separately audited `_stable_ops` library remains
validated across PyTorch 2.10 through 2.13.

Published wheels contain both native backends and do not require an OptiX SDK
at runtime. Building this dual-backend distribution from source does require
the OptiX SDK headers, even when the target machine will select CUDA at
runtime; an SDK-less CUDA-only source-build mode is not currently provided.
Native source builds require CUDA Toolkit 11.3 or newer so the CUDA runtime can
resolve driver entry points lazily without making the wheel depend directly on
the platform CUDA driver library.

## Ray-tracing backend selection

`Scene()` selects OptiX when the current CUDA device and driver expose it and
otherwise selects RayD's pure-CUDA triangle and edge BVHs. The resolved choices
are available through `scene.trace_backend` and `scene.edge_bvh_backend` after
`build()`:

```python
scene = rt.Scene()  # trace_backend="auto", edge_bvh_backend="auto"
scene.add_mesh(mesh)
scene.build()
print(scene.trace_backend, scene.edge_bvh_backend)
```

Pass `trace_backend="optix"` or `"cuda"` and
`edge_bvh_backend="optix"` or `"cuda"` to require a backend. An explicit
OptiX request fails if OptiX is unavailable; runtime pipeline, allocation, and
CUDA errors are never converted into a fallback. `RAYD_DISABLE_OPTIX=1` is the
deployment and test kill switch. Both backends use Torch-owned tensors and the
current Torch CUDA stream.

The separately governed ADR-0029 exact four-sample axial-edge primitive and
ADR-0033 segment-penetration family remain OptiX-only by contract. Requesting
either from a CUDA scene raises an explicit unsupported-backend error; RayD
does not substitute a numerically different implementation.

## SDF Grid Intersection

`rt.SdfGrid` and `rt.sdf_intersect` sphere-trace a caller-owned dense signed
distance field. The grid holds vertex-centred float32 samples of shape
`[Nx, Ny, Nz]` in world-metric distance with the negative-inside sign
convention, placed by an oriented box given as a world centre, a scalar-first
quaternion, and full side lengths:

```python
result = rt.sdf_intersect(
    rt.SdfGrid(values, position=position, rotation=rotation, scale=scale),
    origins,
    directions,
    tmax=10.0,
)
result.t.sum().backward()
```

The march is relaxed, recovers from overshoot by bisecting the bracketing sign
change, and clips the traced interval to the ray/box overlap, so an origin
inside the box is a supported case. `t`, `position`, and `normal` carry
gradients and tangents to the grid values, the box transform, and the rays under
the frozen-winner implicit function theorem; `hit_mask` and `steps` carry none.
Missed lanes report `t = +inf` and are bitwise inert: zero outputs, zero
derivatives, and no atomic contribution. The operation performs no
device-to-host copy and no stream synchronization, including for its
resolution-derived `eps_hit` default.

The primitive is standalone and Torch-only: no OptiX, no `Scene` membership, no
mixing with triangle geometry, and no silhouette gradients in v1. See
[`docs/adr/0037-differentiable-sdf-intersection.md`](../docs/adr/0037-differentiable-sdf-intersection.md).

## Tensor ABI

RayD Torch APIs accept CUDA `torch.float32` tensors for vector data and CUDA `torch.int32` tensors for index data. Vector tensors are row-major `(N, 3)` unless otherwise documented, masks are `torch.bool`, and tensors should be contiguous. Outputs and AD tapes are Torch-owned tensors.

## Gradient Contract

Intersection, edge, reflection, EPC, and diffraction operators use a fixed-winner gradient contract where explicit native kernels exist. The discrete primitive, edge, visibility, or path decision selected in the forward pass is treated as non-differentiable; VJP and JVP propagate through the continuous values recomputed from the saved winner and live Torch tensors.

## Autograd

The native operators support Torch reverse-mode VJP and forward-mode JVP for the supported continuous inputs where explicit kernels have been implemented. CUDA work is launched on the current Torch CUDA stream.

## Native Source Integration

Native downstream projects built in the same CMake/LibTorch graph use the
versioned typed C++ surface in `rayd/integration.h`; they do not load a
second RayD Python extension or use a dynamic symbol registry. Solver-neutral
transmission and scattering device math is exposed through
`src/transmission_device.cuh` and `rayd/scattering_table.cuh`. Torch-specific
cross-concept field AD helpers live at `src/field_transport_ad.cuh`.

The `rayd-torch` wheel also carries a relocatable source bundle at
`rayd/torch/_source`. `rayd-source.json` records the distribution version,
source commit and repository, integration ABI identity, the complete eight-header integration API set and its aggregate SHA-256, the separately bundled `path_exchange.h` contract, and the SHA-256 of a
complete per-file manifest. The bundle contains the canonical include, source,
and build inputs needed for a same-graph native build. Downstreams locate this
passive
resource through `importlib.metadata`; they must not import `rayd.torch`, scan
an environment prefix, or trust the metadata without pinning and recomputing
the full source manifest. An explicit source checkout remains a higher-priority
developer input and keeps its Git identity checks.
See
[`docs/adr/0034-validated-package-source-discovery.md`](../docs/adr/0034-validated-package-source-discovery.md).

The accepted transmission surface consists of complete primal/backward/JVP
families for resident CSR layer-stack evaluation and complete-row Jones field
transport. These operations preserve precise-math compilation, row fusion,
atomic layer-gradient order, and the no-persistent-tape contract. Inputs are
validated before launch, work runs on the caller's current Torch CUDA stream,
and invalid shape/dtype/device/ABI state or CUDA failure raises immediately;
there is no CPU, Torch-expression, finite-difference, or legacy-dispatch
fallback.

RayD owns the numerical primitives and typed native operations, not a
downstream application's material encoding, topology selection, solver
estimator policy, RNG/MIS, accumulation, metadata, or result schema. A newly
merged transmission implementation may remain a dormant candidate until the
consumer pins it, switches all callers, proves parity, and deletes its local
implementation. See
[`docs/adr/0002-shared-rf-transmission-ownership.md`](../docs/adr/0002-shared-rf-transmission-ownership.md).

The accepted diffraction surface will place the complete fixed-winner
pure-wedge field primal/backward/JVP family behind the typed integration header
once the dormant RayD candidate is implemented and direct-tested. Channel
remains the production numerical owner until it pins, validates, activates, and
deletes its local CUDA implementation. The future typed family must preserve
optional winner vertices, three separate native entry launches, current-stream
execution, output schemas, and the family-local `--use_fast_math` contract
required for order-1 exporter parity. Monte Carlo Sionna accumulation, coupled
RD/DD operations, and BDPT estimator policy remain downstream-owned. See
[`docs/adr/0025-diffraction-family-ownership.md`](../docs/adr/0025-diffraction-family-ownership.md).

The accepted generic-scattering surface consists of exactly seventeen typed
operations in six complete families: resident table evaluation AD, resident
table sampling/PDF, single-bounce ensemble, phase-screen patch integral,
chain ensemble, and chain realization. RayD evaluates caller-owned resident
CUDA tensors but does not own table construction, cache/version policy,
phase-screen seed/lifecycle, topology, estimator, RNG/MIS, accumulation, or
result policy. A high-level BSDF/material framework remains out of scope;
solver-neutral RF scattering primitives are in scope.

The migration preserves the existing AD asymmetry: chain-ensemble continuous
geometry supports JVP but reverse-mode requests fail loudly, while
chain-realization supports its existing continuous-geometry VJP and JVP.
Complete row fusion, launch count, recomputation/tape lifetime, backward
atomics, output schemas, and the source-TU compile split are frozen: table
primal/sample/PDF uses default CUDA flags, while the audited table-AD,
ensemble, patch, and chain lockstep TUs retain `--fmad=false`. A merged RayD
implementation remains dormant until Channel pins it, switches a complete
family with parity evidence, and deletes the local implementation. See
[`docs/adr/0026-generic-scattering-runtime-ownership.md`](../docs/adr/0026-generic-scattering-runtime-ownership.md).

The stable source-level boundary is named `rayd/integration.h`, its exact
identity is `rayd.torch.integration`, and its numeric API version is `7`.
No `integration_v2` forwarding header, CMake target alias, or alternate
identity is supported. See
[`docs/adr/0028-stable-typed-integration-naming.md`](../docs/adr/0028-stable-typed-integration-naming.md).

API version 3 makes row validity explicit for pure-wedge diffraction,
transmission sequences, and all generic scattering requests. The required
device boolean tensor is checked before any row payload or ID is read; invalid
primal/JVP rows and supported row gradients are bitwise zero and cannot
contribute shared-gradient atomics. AD companions inherit the mask from their
nested primal request. See
[`docs/adr/0030-typed-capacity-row-validity.md`](../docs/adr/0030-typed-capacity-row-validity.md).

API version 4 additionally makes `DiffractionPathConfig.active` required for
order-1 path export. It is a contiguous CUDA boolean tensor with exact shape
`[state_limit]`; an empty state set carries a defined empty mask. The Python
`Scene.trace_dfr_paths(...)` entry requires the keyword, and neither the typed
API nor dispatcher accepts omitted, `None`, broadcast, or strided validity.
Diffraction accumulation and coherent-accumulation contracts are unchanged. See
[`docs/adr/0031-required-diffraction-path-validity.md`](../docs/adr/0031-required-diffraction-path-validity.md).

The typed boundary also carries a dormant axial-edge visibility candidate for
device-resident diffraction state selection. It consumes broadcast TX and
contiguous AoS edge tensors, evaluates the four exact binary32 fractions in one
separate OptiX launch on the caller's current CUDA stream, and returns a
resident boolean state mask. Its traversal inherits the legacy OptiX compile
policy while inline PTX locks
only point construction to non-FTZ, non-FMA round-to-nearest operations. The
legacy visibility dispatcher is unchanged and cannot select this entry. The
operation adds no synchronization beyond the existing common launch-parameter
staging path; removing that staging path's host event wait is a separate
optimization.
See [`docs/adr/0029-typed-axial-edge-visibility.md`](../docs/adr/0029-typed-axial-edge-visibility.md).

API version 5 adds an explicit `DiffractionPathLayout` to the typed order-1
exporter. Existing callers retain `Compact`; same-graph consumers may request
`SourceLane`, where the fixed row is
`((tx * rx_count + rx) * state_limit) + state`. Rejected lanes remain inert and
the CUDA count remains actual-count metadata rather than a storage ordinal.
Both layouts use the same traversal and UTD implementation. See
[`docs/adr/0032-source-lane-diffraction-path-layout.md`](../docs/adr/0032-source-lane-diffraction-path-layout.md).

API version 6 adds the dormant complete batched segment-penetration family.
Each non-empty structurally active forward call submits one OptiX launch and
performs its ordered `D+1` capacity probe in raygen; an explicit structurally
all-inactive call uses only a same-stream CUDA mask consistency check. Results
and tapes use fixed `[N,D]` storage and the caller's shared device failure
transaction. Backward/JVP use frozen winners and never retrace. RayD exposes no
Python dispatcher for this family, and Channel retains material and wall-product
policy. See
[`docs/adr/0033-batched-segment-penetration.md`](../docs/adr/0033-batched-segment-penetration.md).

RayD Torch carries all seventeen typed operations. Channel has activated the
Phase 10A table, sampling, single-bounce ensemble, and patch-integral entries.
The six Phase 10B chain entries are source-linked into the native core and
direct-tested but remain dormant: no RayD Python binding dispatches them, and
Channel remains their production numerical owner until its atomic
pin/switch/delete commit.

## Current Status

RayD Torch now builds separate native scene, edge, reflection, and diffraction
Torch extension bindings. The native build includes OptiX PTX pipelines for
scene intersection, edge queries, reflection tracing/EPC/visibility/
accumulation, and diffraction path/accumulation/coherent direct execution.

Current opt-in RayD parity tests cover forward cases for scene intersection,
multi-mesh global ids, nearest-edge, visibility, reflection tracing,
diffraction paths, direct/Keller/suffix diffraction accumulation, order-2 and
order-3 diffraction chains, and coherent direct accumulation. Torch VJP/JVP
coverage exists for geometry, edge, reflection trace, EPC, and diffraction
accumulation under the fixed-winner contract.

On the recorded same-script benchmark shape (grid 64, 4,096 queries, warm
caches), RayD Torch currently measures faster than RayD for scene build,
intersect, nearest edge, reflection trace, diffraction paths, and direct
diffraction accumulation. Far-from-surface nearest-edge queries use a tiled
exact fallback scan instead of the scene-diagonal OptiX tier. Release-size and
Nsight-counter-backed runs remain the broader performance gate. See
[`torch_gap_analysis.md`](../docs/torch/torch_gap_analysis.md) and

## Dependencies

RayD Torch depends on PyTorch, CUDA, and OptiX for native execution. The RayD Torch package path has no Dr.Jit dependency.
