Quickstart

One NumPy event

import numpy as np
import flashjet

p4 = np.array([[10., 0., 0., 10.], [2., 0., 0., 2.], [-5., 0., 0., 5.]])
seq = flashjet.cluster(p4, R=0.4)
print(seq.inclusive_jets())       # [[12, 0, 0, 12], [-5, 0, 0, 5]]
print(seq.jet_constituents())     # [[0, 1], [2]]

Each row is (px, py, pz, E) in one consistent unit. NumPy input always uses the float64 reference implementation; backend, mask, and decode do not select a different NumPy path. inclusive_jets(ptmin) uses the strict cut pt > ptmin and returns jets in descending transverse momentum.

A padded tensor batch

import torch
import flashjet

p4 = torch.tensor([[[10., 0., 0., 10.], [2., 0., 0., 2.],
                    [-5., 0., 0., 5.], [0., 0., 0., 0.]]])
p4.requires_grad_()
mask = torch.tensor([[True, True, True, False]])
out = flashjet.cluster(p4, mask, R=0.4)
jets = out.jets_p4(p4)
sorted_jets, order = out.sort_jets_by_pt(jets)
sorted_jets[..., 3].sum().backward()

p4 has shape (batch, particles, 4). Use float32 or float64. mask has shape (batch, particles), is Boolean, and lives on the same device. Omit it only when every slot is a real particle. Padding gets assignment -1.

Move both inputs to CUDA for GPU execution. backend="auto" chooses a backend from the padded width and device; see Backends.

out.n_jets counts jets per event. Tensor jets start in beam-removal order, not momentum order. If you sort the momenta, apply the returned order to any per-jet features too. Requesting a smaller n_jets_max drops higher-index jets; it is not a cut on transverse momentum.

Algorithms and gradients

Choose algorithm="antikt", "kt", or "cambridge". The aliases "anti-kt", "ca", and "cambridge-aachen" also work. p= overrides the algorithm with a generalized-kt exponent. Use a finite positive R and finite input momenta.

Clustering decisions run without gradients. jets_p4() sums the selected particles with PyTorch operations, so derivatives flow through that fixed assignment. This does not differentiate changes in jet membership.