This repository contains a complete simulation and analysis pipeline for a photophilic axion-like particle (ALP) search at electron-positron colliders. The signal process is
with the effective interaction
The pipeline is set up to do three things:
- Check the analytic formulas against MadGraph and the Belle II public limit.
- Generate ALP signal and Standard Model background samples through MadGraph, Pythia, and Delphes.
- Build FCC-ee Z-pole projected sensitivity contours and overlay them on the existing ALP-photon landscape.
The default FCC-ee setup is the Z pole,
From a fresh clone, set up the local Python environment:
python3 -m venv .venv
source .venv/bin/activate
pip install -r env/requirements.txtClone the external AxionLimits data if you want to rebuild the landscape plots or rerun the Belle II closure:
git clone https://github.com/cajohare/AxionLimits.git external/AxionLimits
cd external/AxionLimits
git checkout 7d375f4879b32406a239fe48d2615a4bfd9bc0bb
cd ../..Then the local, pure-Python chain is:
make theory-grid
make belle2-closure
make projection
make background-signal-examples
make money-plotsor, in one go:
make local-allRun this if you just want to check that the Python scripts compile:
.venv/bin/python -m py_compile analysis/*.py theory/predictions/*.py mc/make_param_card.py.
├── analysis/ Python background building, limits, plots, efficiency maps
│ └── configs/ Locked JSON inputs for Belle II, FCC-ee, AxionLimits
├── condor/ HTCondor point lists and submit files for Nikhef/Stoomboot
├── env/ Python requirements and Nikhef LCG setup helper
├── external/ Local external checkouts, especially AxionLimits
├── literature/ Reference papers kept outside the runnable pipeline
├── mc/ MadGraph, Pythia, Delphes cards and production wrappers
├── models/ALP_linear/ UFO model used by MadGraph
├── results/ Compact CSV, JSON, PNG, and PDF outputs
└── theory/predictions/ Analytic formulas and validation tools
The detailed READMEs are:
| README | What it covers |
|---|---|
env/README.md |
Python environment and Nikhef LCG setup. |
theory/predictions/README.md |
Analytic grid, cross-section checks, Belle II closure. |
mc/README.md |
MadGraph, Pythia, Delphes signal/background production. |
condor/README.md |
Batch production on the Nikhef Stoomboot cluster. |
analysis/README.md |
Background histograms, contours, efficiency maps, plotting. |
results/README.md |
Meaning of the checked-in result files. |
external/README.md |
How external data repositories are expected to live here. |
The code uses:
- mostly-minus metric;
-
$\epsilon^{0123}=+1$ ; -
$g_{a\gamma\gamma}$ in$\mathrm{GeV}^{-1}$ ; -
$\hbar c=1.973269804\times10^{-16},\mathrm{GeV,m}$ ; -
$\Gamma(a\to\gamma\gamma)=g_{a\gamma\gamma}^2m_a^3/(64\pi)$ .
The main analytic formulas are
and
These are implemented in theory/predictions/predict_grid.py and used by the
validation and projection scripts.
The full analysis runs in this order:
1. Analytic prediction grid
2. Belle II public-contour closure
3. MadGraph ALP signal production
4. Pythia ALP decay/lifetime and HepMC writing
5. Delphes detector simulation
6. Detector-level signal validation
7. Standard Model background production
8. Binned background histograms
9. Detector efficiency/correction map
10. FCC-ee projected contours
11. Signature classification map
12. AxionLimits landscape and money plots
The dense contour is not made by running Delphes at every
Build the theory grid:
.venv/bin/python theory/predictions/predict_grid.py \
--out theory/predictions/theory_grid.csvUseful variants:
.venv/bin/python theory/predictions/predict_grid.py \
--sqrt-s 10.58 \
--out theory/predictions/theory_grid_belle2.csv
.venv/bin/python theory/predictions/predict_grid.py \
--sqrt-s 91.2 \
--fccee-l-min 0.02 \
--fccee-l-max 2.5 \
--out theory/predictions/theory_grid_fccee.csvMain script:
| Script | Role |
|---|---|
theory/predictions/predict_grid.py |
Computes |
Run the closure against the public Belle II curve in AxionLimits:
.venv/bin/python theory/predictions/validate.py \
--belle2-closure \
--axionlimits-dir external/AxionLimitsOutputs:
results/belle2_closure/belle2_closure.png
results/belle2_closure/belle2_closure.pdf
results/belle2_closure/belle2_closure_summary.json
results/belle2_closure/belle2_closure_contour.csv
Main scripts:
| Script | Role |
|---|---|
analysis/belle2_closure.py |
Reconstructs the public Belle II boundary using the same production/lifetime logic used later for FCC-ee. |
theory/predictions/validate.py |
Runs the closure and writes pass/fail summaries. |
The checked-in FCC-ee result can be rebuilt from the compact CSV/JSON files in
results/fccee/:
.venv/bin/python analysis/fccee_projection.py \
--config analysis/configs/fccee_zpole_inputs.json \
--out-dir results/fccee \
--background-yields results/fccee/fccee_background_yields.csv \
--background-bins results/fccee/fccee_background_bins.csv \
--n-mass 180 \
--n-g 180Outputs:
results/fccee/fccee_projection.csv
results/fccee/fccee_projection_summary.json
results/fccee/fccee_zpole_signature_classification.csv
results/fccee/fccee_zpole_signature_classification.png
Main scripts:
| Script | Role |
|---|---|
analysis/fccee_projection.py |
Solves invisible and prompt-resolved projected contours and writes the topology map. |
analysis/build_full_analysis_efficiency_map.py |
Converts detector-level signal samples into correction factors for the contour. |
Build the background-plus-signal comparison plot:
.venv/bin/python analysis/plot_background_signal_examples.py \
--config analysis/configs/fccee_zpole_inputs.json \
--out-png results/fccee/background_signal_examples.png \
--out-pdf results/fccee/background_signal_examples.pdf \
--summary-csv results/fccee/background_signal_examples_summary.csvBuild a CMS-style prompt-resolved invariant-mass plot for one ALP point:
.venv/bin/python analysis/plot_prompt_resolved_invariant_mass.py \
--mass 20.0 \
--coupling 5e-4 \
--x-min 10.0 \
--x-max 30.0 \
--out results/fccee/prompt_resolved_invariant_mass_example.pngMain scripts:
| Script | Role |
|---|---|
analysis/plot_background_signal_examples.py |
Shows binned backgrounds with example ALP templates. |
analysis/plot_prompt_resolved_invariant_mass.py |
Builds a two-panel |
Build the ALP-photon landscape without FCC-ee overlays:
.venv/bin/python analysis/make_axionlimits_style_plot.py \
--axionlimits-dir external/AxionLimits \
--projection results/fccee/fccee_projection.csv \
--constraint-set full \
--no-fcc-ee \
--output-stem results/fccee/axionlimits_alp_landscape_intro \
--combined-output-stem results/fccee/axionlimits_alp_landscape_introBuild the FCC-ee close-up money plot:
.venv/bin/python analysis/make_axionlimits_style_plot.py \
--axionlimits-dir external/AxionLimits \
--projection results/fccee/fccee_projection.csv \
--constraint-set full \
--output-stem results/fccee/money_plot_alp_full_closeup \
--also-save-as results/fccee/money_plot \
--m-min 1e7 \
--m-max 1e12 \
--g-min 1e-8 \
--g-max 1e-1The plotting code uses AxionLimits masses in eV internally, so the close-up
range above corresponds to
Main script:
| Script | Role |
|---|---|
analysis/make_axionlimits_style_plot.py |
Loads AxionLimits and overlays FCC-ee projection contours. |
For a single detector-level ALP point:
source env/setup_nikhef_lcg.sh
mc/alp_signal/run_alp_full_pipeline.sh \
results/alp_full_pipeline/example_fccee \
1000 91.2 1.0 1e-5 \
mc/delphes_cards/delphes_card_IDEA.tcl \
resolved_promptThat wrapper does:
param_card -> MadGraph LHE -> Pythia HepMC -> Delphes ROOT
-> theory validation -> detector histogram validation
Main files:
| File | Role |
|---|---|
mc/make_param_card.py |
Writes a point-specific ALP parameter card. |
mc/alp_signal/run_alp_full_pipeline.sh |
Runs one full ALP point end to end. |
mc/alp_signal/run_alp_pythia_delphes.cc |
Pythia8 ALP decay/lifetime and HepMC writer. |
analysis/alp_pipeline_histograms.py |
Validates detector-level photons, invariant masses, and recoil energies. |
theory/predictions/validate.py |
Checks cross section, width/lifetime convention, and file outputs. |
For one background sample:
source env/setup_nikhef_lcg.sh
mc/backgrounds/run_sm_background_full_pipeline.sh \
results/backgrounds/fccee_resolved_3gamma \
resolved_3gamma \
10000 \
91.2 \
mc/delphes_cards/delphes_card_IDEA.tclThe two FCC-ee backgrounds used by the contour are:
| Label | Process | Observable |
|---|---|---|
resolved_3gamma |
diphoton invariant mass | |
invisible_gamma_nunu |
recoil-photon energy |
After the Delphes ROOT files exist, build the background inputs:
.venv/bin/python analysis/fccee_background_yields.py \
--resolved-root <resolved_3gamma_delphes.root> \
--resolved-banner <resolved_3gamma_banner.txt> \
--invisible-root <invisible_gamma_nunu_delphes.root> \
--invisible-banner <invisible_gamma_nunu_banner.txt> \
--out results/fccee/fccee_background_yields.csv
.venv/bin/python analysis/fccee_binned_background.py \
--resolved-root <resolved_3gamma_delphes.root> \
--resolved-banner <resolved_3gamma_banner.txt> \
--invisible-root <invisible_gamma_nunu_delphes.root> \
--invisible-banner <invisible_gamma_nunu_banner.txt> \
--out results/fccee/fccee_background_bins.csv \
--summary-json results/fccee/fccee_background_bins_summary.jsonMain scripts:
| Script | Role |
|---|---|
mc/backgrounds/run_sm_background_full_pipeline.sh |
Runs one SM background sample through MG5, Pythia, and Delphes. |
analysis/fccee_background_yields.py |
Builds single-window diagnostic background yields. |
analysis/fccee_binned_background.py |
Builds binned background histograms for the Asimov limit. |
On Nikhef/Stoomboot, the batch entrypoints are:
condor_submit condor/submit_background_scan.sub
condor_submit condor/submit_alp_full_projection_scan.subAfter the full ALP campaign finishes:
.venv/bin/python analysis/collect_alp_full_scan.py \
results/alp_full_production/fccee_z_full_projection_fullbg_channelaware \
--out results/fccee/alp_full_scan_summary.csv \
--summary-json results/fccee/alp_full_scan_summary.jsonMain files:
| File | Role |
|---|---|
condor/background_points_fccee_z.txt |
Two FCC-ee background jobs. |
condor/alp_full_points_fccee_z_projection.txt |
Detector-level ALP points around the projected contours. |
condor/submit_background_scan.sub |
Background submit file. |
condor/submit_alp_full_projection_scan.sub |
Full ALP signal submit file. |
analysis/collect_alp_full_scan.py |
Collects per-point summaries into results/fccee/. |
More details are in condor/README.md.
Belle II:
results/belle2_closure/belle2_closure.png
results/belle2_closure/belle2_closure.pdf
results/belle2_closure/belle2_closure_summary.json
results/belle2_closure/belle2_closure_contour.csv
FCC-ee:
results/fccee/fccee_projection.csv
results/fccee/fccee_projection_summary.json
results/fccee/fccee_zpole_signature_classification.csv
results/fccee/fccee_zpole_signature_classification.png
results/fccee/background_signal_examples.png
results/fccee/prompt_resolved_invariant_mass_example.png
results/fccee/money_plot.png
results/fccee/money_plot.pdf
The checked-in FCC-ee Z-pole projection has:
| Branch | Mass span | Coupling span |
|---|---|---|
| Invisible lower |
|
|
| Invisible upper |
|
|
| Prompt-resolved |
|
|
The invisible lower branch and prompt-resolved branch are the most stable headline contours. The invisible upper branch is a short-lifetime boundary and is more sensitive to detector and lifetime modeling.
The full signature grid has
| Topology | Points |
|---|---|
| prompt-resolved | 14,171 |
| invisible | 10,452 |
| merged | 5,989 |
| displaced-resolved | 1,788 |
The Belle II closure is a public-contour closure, not a reimplementation of the private Belle II likelihood. The FCC-ee contours include leading SM backgrounds and Delphes-derived correction factors, but they do not include full detector systematics, beam-induced backgrounds, object misidentification, or dedicated displaced/merged reconstruction.