Theory Nuisance Parameter estimates of perturbative QCD missing higher-order uncertainties
Project description
PUNTer
PUNTer is a small analysis tool for estimating missing higher-order uncertainties (MHOU) in fixed-order perturbative QCD using theory nuisance parameters (TNPs).
The implementation is based on:
- Matthew A. Lim and Rene Poncelet, Robust estimates of theoretical uncertainties at fixed-order in perturbation theory, arXiv:2412.14910
Motivation
The code provides estimates of missing higher-order QCD uncertainties for fixed-order calculations, following the TNP approach described in arXiv:2412.14910. In practical terms:
- a fixed-order prediction is written as a perturbative expansion in alpha_s
- the unknown next term is modelled using nuisance parameters
- the nuisance parameters multiply lower-order information with a simple polynomial dependence on the kinematics
- varying those nuisance parameters gives an uncertainty band and a covariance matrix.
PUNTer takes as input higher order calculations produced by external codes and returns a TNP-based MHOU estimate.
What The Code Does
The main entry point is punter.py. It can:
- read fixed-order predictions from several external formats
- build the perturbative expansion order by order
- evolve
alpha_sfromM_Zto bin scales, or keep it fixed - model the next missing term using Chebyshev, Legendre, or Bernstein bases
- save central values, uncertainty bands, coefficient matrices, covariance matrices, and replicas
- plot the result with bin-edge aware step plots
- run from CLI flags or from a YAML config file
- process one observable or a batch of observables in one run
Supported Input Formats
The current implementation supports:
yodastrippern3loxsmatrixnnlojetmcfmgeneva
Format detection is automatic in many common cases, but can be forced with --format.
Format Conventions
PUNTer normalizes several external fixed-order formats into a common internal representation, but the way observables are identified differs by provider.
yoda:targetis the YODA object path, for example/MY_ANALYSIS/PT_JETstripper:targetis the<observable><description>text in the XML filematrix:targetis matched against the observable name embedded in the filename, andrun_modemust match the MATRIX run suffix such asLORUN,NLORUN, orNNLORUNn3loxs: files are binned byqminand notargetis requirednnlojet: each file corresponds to one histogram; the observable name and perturbative order are read from the filename itselfmcfm:targetis matched against the TopDrawer plot titlegeneva:targetis matched against the distribution name inside the XML/CDATА payload
For nnlojet in particular, the filename convention matters. The loader expects the perturbative order and observable name to come from the filename, for example:
proc.LO.ptj1_a.s1.datproc.NLO.LO.ptj1_a.s1.datproc.NNLO.NLO.LO.ptj1_a.s1.dat
In that scheme, ptj1_a is the observable name and must match target exactly. This avoids accidental matches such as ptj1_a versus ptj1_2plus_a.
Installation
The project now has a standard pyproject.toml and can be installed as a package.
Core dependencies:
numpyscipy
Optional dependencies:
matplotlibfor plottingPyYAMLfor YAML config filesqcdevolforalpha_srunningbabyyodafor pip-installable YODA-compatible parsing
A minimal editable install is:
python -m pip install -e .
For optional plotting, YAML config support, and external parser/running helpers:
python -m pip install -e .[full]
For YODA support specifically:
python -m pip install -e .[yoda]installsbabyyoda, which provides a pip-installable YODA-compatible reader- if the official HEP YODA Python bindings are already installed in your environment, PUNTer will use them directly
- PUNTer intentionally does not depend on the PyPI package named
yoda, because that import name can resolve to an unrelated project
On PyPI, the distribution name is punter-hep:
python -m pip install punter-hep
This installs the punter console command and the punter Python package. Legacy usage with python punter.py still works as a compatibility shim.
Package Layout
The repository is now organized as a package:
punter/core.py:Punterclass and core perturbative computationpunter/api.py: public library entrypointspunter/formats.py: normalized format loaderspunter/io/parsers.py: raw file-format parserspunter/cli.py: command-line and YAML-driven executionpunter/types.py: typed public data objectspunter/__main__.py:python -m punterpunter.py: compatibility entrypointpyproject.toml: package metadata and console script definition
Public Python API
The package now exposes a small typed library API intended to be more stable than the internal implementation details.
Main public objects:
FitResultObservableInputRunConfigPredictionResultReplicaResult
Main public functions:
create_punter(...)fit_tnp(...)generate_replicas(...)load_yoda_observable(...)load_observable(...)run_tnp(...)
Example:
from punter import RunConfig, load_yoda_observable, run_tnp
observable = load_yoda_observable(
["results/lo.yoda", "results/nlo.yoda", "results/nnlo.yoda"],
"/MY_ANALYSIS/PT_JET",
cumulative=True,
)
result = run_tnp(
observable,
RunConfig(
coupling=0.118,
model="Bernstein",
degree=2,
theta_range=1.0,
),
)
print(result.central)
print(result.covariance)
Library-side fit example:
from punter import RunConfig, fit_tnp, generate_replicas, load_observable
observable = load_observable(
["results/lo.yoda", "results/nlo.yoda"],
"yoda",
target="/MY_ANALYSIS/PT_JET",
cumulative=True,
)
fit = fit_tnp(
observable,
truth_values=[...], # one value per bin
truth_errors=[...], # one positive uncertainty per bin
config=RunConfig(coupling=0.118, model="Chebyshev", degree=1),
)
replicas = generate_replicas(
observable,
RunConfig(coupling=0.118, n_replicas=50, seed=7),
)
At the moment, the normalized loader path is implemented first for YODA inputs. Other format-specific loaders still primarily live behind the existing Punter.from_* classmethods.
The normalized loader path currently supports:
yodastrippermatrixn3loxsnnlojetmcfmgeneva
The CLI now uses this normalized loader layer for all supported formats before constructing the computation engine.
CI/CD
The repository includes GitHub Actions workflows for validation and releases:
.github/workflows/ci.ymlruns linting, mypy, the unit test suite on Python 3.10 to 3.12, and package build validation on pushes and pull requests.github/workflows/release.ymlbuilds release artifacts for version tags matchingv*, publishes a GitHub Release with the built wheel and source tarball, and publishes to PyPI when thePYPI_API_TOKENrepository secret is configured
Recommended release flow:
- Bump the package version.
- Push a tag such as
v0.3.0. - Let the release workflow build and attach the artifacts.
- Configure
PYPI_API_TOKENif you want the same tagged release to publish automatically to PyPI.
Basic Usage
Command-line
Single observable:
punter results/*.yoda \
--format yoda \
--target /MY_ANALYSIS/PT_JET \
--model Bernstein \
--degree 2 \
--save \
--plot
Process multiple observables in one call:
punter results/*.yoda \
--format yoda \
--targets /MY_ANALYSIS/PT_JET /MY_ANALYSIS/M_JJ \
--model Chebyshev \
--save \
--plot
Save seeded replicas:
punter input_qmin20.txt \
--format n3loxs \
--save-replicas \
--n-replicas 200 \
--seed 12345
Show all CLI options:
punter --help
YAML Config
You can also drive runs from YAML.
Single run:
files:
- data/result.yoda
format: yoda
target: /MY_ANALYSIS/PT_JET
coupling: 0.118
model: Bernstein
degree: 2
save: true
plot: true
save_cov: true
save_replicas: true
n_replicas: 100
seed: 42
Run with:
punter --config run.yaml
YAML configs are validated before any files are loaded. In particular:
- unknown keys are rejected, so typos like
savfail immediately defaultsmust be a mapping andrunsmust be a list of mappingsfilesandtargetsmust be non-empty lists of strings- scalar fields such as
coupling,mZ,theta_range,degree,n_replicas, andseedare type-checked format,model, andorderare checked against the supported choicestargetandtargetscannot both be present in the same merged run
Supported YAML run keys are:
files, format, coupling, mZ, target, targets, cumulative, run_mode,
model, degree, order, alphas_run_order, fix_scale, fit, save, save_coeffs, save_cov,
save_replicas, plot, show_plot, log_y, n_replicas, theta_range,
seed, output_dir, plot_title
Batch config:
defaults:
files:
- data/result.yoda
format: yoda
coupling: 0.118
model: Chebyshev
degree: 2
save: true
runs:
- target: /MY_ANALYSIS/PT_JET
plot: true
- targets:
- /MY_ANALYSIS/M_JJ
- /MY_ANALYSIS/DELTA_Y
save_cov: true
save_replicas: true
n_replicas: 50
seed: 7
Main Options
Physics and model setup:
--coupling: value ofalpha_s(M_Z)--mZ: reference scale for the input coupling--fix-scale: disable running and use a fixed coupling--order {NLO,NNLO,N3LO}: truncate to a requested perturbative order--alphas-run-order {0,1,2,3}: loop order foralpha_srunning--model {Chebyshev,Chebyshev0,Legendre,Legendre0,Bernstein}--degree: polynomial degree
Outputs:
--save [FILE]: save central values and TNP uncertainty--save-coeffs [FILE]: save coefficient matrix--save-cov [FILE]: save covariance matrix--save-replicas [FILE]: save replicas--plot [FILE]: save a plot--show-plot: display the plot interactively--output-dir DIR: directory for auto-generated filenames
Replica generation:
--n-replicas: number of replicas--seed: random seed for reproducibility
Batch/config:
--targets: run multiple observables in one CLI invocation--config: read one or more runs from YAML
Output Files
By default, output filenames are generated automatically with the pattern:
punter_<format>_<target>_<suffix><extension>
where:
<format>is the sanitized input format name<target>is the sanitized observable name, omitted when no target exists<suffix>is one ofresults,coeffs,covariance,replicas, orplot<extension>is.csvfor tabular outputs and.pngfor plots
Sanitization rules for <format> and <target> are:
- non-alphanumeric characters are replaced with
_ - leading and trailing
_are stripped - the result is lower-cased
Examples:
punter_yoda_my_analysis_pt_jet_results.csvpunter_yoda_my_analysis_pt_jet_covariance.csvpunter_yoda_my_analysis_pt_jet_replicas.csvpunter_yoda_my_analysis_pt_jet_plot.png
If an output flag is given an explicit filename, that filename is used as-is.
For multi-target runs:
- automatic filenames are generated independently per target
- if a user supplies a single explicit filename, PUNTer appends
_<sanitized-target>before the file extension - if a user supplies a template containing
{target},{format}, or{suffix}, those placeholders are substituted directly
Examples:
--savewith target/REF/HISTO_Abecomespunter_yoda_ref_histo_a_results.csv--save output.csvwith two targets becomesoutput_ref_histo_a.csvandoutput_ref_histo_b.csv--save results_{target}_{suffix}.csvbecomesresults_ref_histo_a_results.csv
CSV output schemas are part of the supported interface.
results CSV:
- columns:
BinLow,BinHigh,Scale,CentralValue,ErrorPlus,ErrorMinus - one row per bin
coeffs CSV:
- columns:
BinLow,BinHigh,Scale,Theta_0,...,Theta_{N-1} - one row per bin
Nis the number of nuisance parameters for the chosen model
covariance CSV:
- columns:
Bin_0,...,Bin_{n_bins-1} - one row per bin
- the file stores the full bin-by-bin covariance matrix
replicas CSV:
- columns:
BinLow,BinHigh,Scale,Replica_0,...,Replica_{n_replicas-1} - one row per bin
Saved tabular outputs always include bin-edge information for results, coeffs, and replicas. covariance is matrix-shaped and therefore uses bin-index headers instead.
Internal Model Choices
The code currently supports several polynomial bases for the kinematic dependence of the missing term:
BernsteinChebyshevChebyshev0LegendreLegendre0
The 0 variants include an additional order-independent polynomial component. In the paper, Bernstein and Chebyshev parameterisations are used in different examples, with k = 2 being the default choice studied there. The default CLI setup in this repository also uses polynomial degree 2.
Notes On Coupling Running
If bin scales are available and --fix-scale is not used, punter evolves alpha_s(M_Z) to the bin scales.
- If
qcdevolis installed, it is used - otherwise the internal running-coupling implementation is used
For observables that look dimensionless from their name, the CLI applies a fixed-scale heuristic automatically unless --fix-scale was already requested explicitly.
Development And Tests
Run the unit tests with:
python -m unittest -q
The repository also ships real parser fixtures under example-outputs. These are used in regression tests to verify that parsing works against representative outputs from external fixed-order codes, not just synthetic minimal examples.
For local development tooling:
python -m pip install -e .[dev]
Configured tools:
rufffor linting and import ordering on the stabilized public API surfacemypyfor gradual type checking of the stabilized public API surfacebuildfor packaging validation
Convenience commands are provided in Makefile:
make test
make lint
make typecheck
make check
make build
make validate-package
The current tool configuration lives in pyproject.toml.
At the moment, type checking covers the public API, computation, CLI, and raw parser layers. Linting is still intentionally focused on the stabilized public surface rather than the full legacy codebase.
make validate-package builds both sdist and wheel artifacts, installs the wheel into a clean local virtual environment, and smoke-tests import punter plus the punter --help entrypoint.
Versioning
The package version is exposed as punter.__version__ and comes from punter/_version.py. Release history is tracked in CHANGELOG.md.
Citation
If you use this code in scientific work, please cite the paper it is based on:
@article{Lim:2024nsk,
author = "Lim, Matthew A. and Poncelet, Rene",
title = "{Robust estimates of theoretical uncertainties at fixed-order in perturbation theory}",
eprint = "2412.14910",
archivePrefix = "arXiv",
primaryClass = "hep-ph",
reportNumber = "IFJPAN-IV-2024-15",
doi = "10.1103/7g5k-4y3v",
journal = "Phys. Rev. D",
volume = "112",
number = "11",
pages = "L111901",
year = "2025"
}
Repository Status
This repository is now installable as a package and has a stabilized public API surface, typed core/CLI/parser layers, documented output contracts, and regression tests against both synthetic inputs and real example outputs. It is still best viewed as an actively evolving research codebase rather than a mature long-term-stability library.
What is relatively stable today:
- the public Python entrypoints in
punter/api.py - the normalized loaders in
punter/formats.py - the command-line interface in
punter/cli.py - the typed data objects in
punter/types.py - the documented output filename rules and CSV schemas in this README
- the format conventions documented above, including NNLOJET filename-based observable matching
What should still be treated as implementation detail:
- internal numerical organization inside
punter/core.py - parser details beyond the documented input conventions and tested fixture coverage
- undocumented behavior that is not described in this README or covered by tests
The most reliable way to understand exact current behavior is:
- the CLI help in
punter.py - the unit tests in
test_punter.py - the shipped parser fixtures in
example-outputs - the methodology paper at arXiv:2412.14910
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file punter_hep-0.3.0.tar.gz.
File metadata
- Download URL: punter_hep-0.3.0.tar.gz
- Upload date:
- Size: 39.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0248eeecd95b1005dfce485e76da6e6908fa0b42a85cb72894dc743a3a1de61e
|
|
| MD5 |
1bf6f7b8d9983e073934987ab0a196c4
|
|
| BLAKE2b-256 |
e9e2c828a4fb65c834a76992fa4c7bc98a1ab208472e19fa179e24f310586125
|
File details
Details for the file punter_hep-0.3.0-py3-none-any.whl.
File metadata
- Download URL: punter_hep-0.3.0-py3-none-any.whl
- Upload date:
- Size: 34.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
17e95e9f669ba4bdf5ad74f91c0d6069f7506994b73e56847255fb12eef1176b
|
|
| MD5 |
2de0888b2e216c19a69b3db10efb09be
|
|
| BLAKE2b-256 |
220dce04625f4a9fcce82396b57e668b54f3b0ba88f53a34d166cd95974c5d4e
|