When to use this
Use this recipe when you are running a resonance search with boosted objects — heavy Higgs → ZV, W′/Z′, X → tt̄, and similar — and you need a jet tagger that does not deform the background mass spectrum. Any standard neural tagger trained on jet features will implicitly learn the jet mass, making cuts on its score sculpt the background and create fake bumps in your bump-hunt.
This recipe replaces the learned feature extractor with the wavelet scattering transform, producing dimensionless r₂ = S₂/S₁ features that are scale-invariant by construction. A DisCo penalty in the classifier training then drives the residual statistical dependence between the tagger score and the resonance mass to zero on background events.
The result is validated by two numbers: the significance gain Δσ over the NN baseline, and the Jensen–Shannon divergence ΔJSD measuring background mass-shape distortion before and after the cut. Both are computed against your existing Wilks Δχ² pipeline — no re-optimisation of the analysis required.
What it needs
Jet constituent four-vectors (ROOT TTree or HDF5) or pre-rasterised 64×64 η×φ jet images. The following branch names are expected by default and can be overridden via config:
# ROOT TTree expected branches
fatjet_constituent_pt # float[N] — per-constituent pT in GeV
fatjet_constituent_eta # float[N] — pseudorapidity
fatjet_constituent_phi # float[N] — azimuthal angle (radians)
fatjet_constituent_e # float[N] — energy in GeV
reco_zv_mass # float — reconstructed resonance mass (GeV)
FullEventWeight # float — MC event weight
isSignal # int — 1 for signal, 0 for background
# Alternatively: pre-rasterised jet image
# shape: (N_events, 64, 64, 1) — float32, HDF5 dataset "jet_image"How it works
MCP tool call sequence
vikshep/ingest
vikshep/compute_scattering
vikshep/reduce_scattering
method="ratio". Computes r₂[λ₁, λ₂] = S₂[λ₁, λ₂] / S₁[λ₁] for all valid (λ₁, λ₂) pairs (j₂ > j₁). Drops S₀ and the lowest-j S₁ entries (they carry the pT scale). The result is a dimensionless feature vector invariant to overall energy scale.vikshep/train_classifier_disco
(export)
What you get
- →classifier.h5 — trained MLP weights (portable, no runtime dependency on Vikshep)
- →benchmark.json — { auc, jsd_precut, jsd_postcut, delta_sigma, lambda_optimal }
- →mass_hist.root — background mass histograms pre/post cut, for visual inspection
- →feature_oids.txt — SHA3-256 OIDs of intermediate scattering tensors (reusable)
- →r2_features.h5 — exported r₂ feature matrix, shape (N_events, n_pairs)
Configure it
| param | default | description |
|---|---|---|
| dim | 2 | Input dimensionality (jet images are 2-D) |
| group | so2 | Symmetry group — SE(2) roto-translation for 2-D images |
| J | 4 | Number of octaves (scales). Higher J = longer range correlations |
| Q | 1 | Voices per octave. Q=1 is sufficient for jet substructure |
| L | 8 | Orientations in [0, π). L=8 gives 22.5° resolution |
| order | 2 | Maximum scattering order. order=2 captures >99% of jet energy |
| pad_phi | Circular | Azimuthal axis is periodic — use circular convolution |
| pad_eta | ZeroPad | η axis is non-periodic — zero-pad to next power of two |
| lambda_grid | 0,0.1,0.5,1,2,5,10 | DisCo penalty strengths swept during training |
| mass_branch | reco_zv_mass | Branch name for the resonance mass (override as needed) |
Run it — CLI
bun run main.ts process \
--input data/jets.root \
--recipe hep-tagging-disco \
--mass-branch reco_zv_mass \
--lambda-grid "0,0.1,0.5,1,2,5,10" \
--output results/hep-tagging/Run it — Dashboard
⬜
Dashboard screenshot — coming in Pilot
The Vikshep dashboard shows the mass histogram before and after the cut, the JSD live readout as λ is swept, and a side-by-side significance comparison against the existing NN baseline. Available in the Pilot release.