Package Overview#
BSSUnfold is a Python package for neutron spectrum unfolding from Bonner Sphere Spectrometers (BSS). It provides 27 unfolding algorithms, 25 spectrum comparison metrics, ICRP-116 dose calculations, and Monte Carlo uncertainty quantification. Iterative solvers are accelerated with Numba JIT compilation.
Unfolding Methods#
All 27 methods are accessible as instance methods on the
bssunfold.Detector class. They are organised into the following
categories:
graph TD
A["Unfolding Methods"] --> B["Tikhonov-type"]
A --> C["Iterative"]
A --> D["Bayesian"]
A --> E["Maximum Entropy"]
A --> F["Statistical Regularization"]
A --> G["Optimization-based"]
A --> H["Pipeline"]
A --> I["Parametric"]
B --> B1["unfold_cvxpy"]
B --> B2["unfold_qpsolvers"]
B --> B3["unfold_tsvd"]
B --> B4["unfold_tikhonov_legendre"]
C --> C1["unfold_landweber"]
C --> C2["unfold_mlem"]
C --> C3["unfold_mlem_stop"]
C --> C4["unfold_mlem_odl"]
C --> C5["unfold_gravel"]
C --> C6["unfold_doroshenko"]
C --> C7["unfold_kaczmarz"]
D --> D1["unfold_bayes"]
D --> D2["unfold_bayes_spline_regularization"]
E --> E1["unfold_maxed"]
F --> F1["unfold_statreg"]
F --> F2["unfold_reconst"]
G --> G1["unfold_lmfit"]
G --> G2["unfold_scipy_direct_method"]
H --> H1["unfold_combined"]
I --> I1["unfold_parametric"]
I --> I2["unfold_parametric_cvxpy"]
I --> I3["unfold_parametric_qpsolvers"]
I --> I4["unfold_parametric_combined"]
I --> I5["unfold_parametric2"]
I --> I6["unfold_fruit_like"]
I --> I7["unfold_hybrid_parametric"]
I --> I8["unfold_bayesian_parametric"]
style A fill:#4a90d9,color:#fff
style B fill:#e8f0fe
style C fill:#e8f0fe
style D fill:#e8f0fe
style E fill:#e8f0fe
style F fill:#e8f0fe
style G fill:#e8f0fe
style H fill:#e8f0fe
style I fill:#e8f0fe
Method Reference#
Note
Common parameters shared by most methods:
readings, initial_spectrum, calculate_errors, noise_level,
n_montecarlo, save_result, random_state.
See the Index or Detector Class for complete API signatures.
Built-in Response Functions#
7 response function datasets are included as Python dicts, importable from the package root:
Dataset |
Source |
Detectors |
Energy Range |
Notes |
|---|---|---|---|---|
|
GSF (Germany) |
10 (0in–18in) |
1e-9 – 631 MeV |
Standard range |
|
PTB (Germany) |
15 (0in–18in) |
1e-9 – 631 MeV |
Standard range |
|
LANL (USA) |
11 (3in–18in) |
1e-9 – 631 MeV |
Includes Pb-shielded (9inPb, 12inPb, 18inPb) |
|
JINR (Dubna) |
9 (0in–12in) |
1e-9 – 631 MeV |
Includes Cd-covered (Cd0in) and Pb-shielded (10inPb) |
|
Fermilab (USA) |
8 (0in–18in) |
1e-9 – 631 MeV |
Standard range |
|
EURADOS round-robin |
13 (0in–12in) |
1e-9 – 20 MeV |
Narrower range; includes Cd2in, 3.5in, 4.5in |
|
IHEP (Protvino) |
12 (0in–18in) |
1e-9 – 2000 MeV |
Wider range; includes 15in |
Warning
RF_EURADOS max energy is 20 MeV and RF_IHEP max energy is 2000 MeV,
compared to 631 MeV for the other datasets. Use caution when comparing
results across datasets with different energy ranges.
from bssunfold import Detector, RF_JINR
detector = Detector(RF_JINR)
result = detector.unfold_cvxpy(readings, regularization=1e-4)
Dose Conversion Coefficients#
4 dose conversion coefficient datasets are included for flexible dose rate calculations. The default is ICRP-116 effective dose.
Dataset |
Standard |
Quantities |
Energy Range |
Notes |
|---|---|---|---|---|
|
ICRP-116 |
AP, PA, LLAT, RLAT, ISO, ROT |
1e-9 – 631 MeV |
Standard range |
|
ICRP-74 |
AP, PA, RLAT, ROT, ISO |
1e-9 – 398 MeV |
Effective dose |
|
NRB99-2009 |
AP, ISO |
25 eV – 20 MeV |
Limited range |
|
ICRP-74 |
ADE, PDE0, PDE45, PDE60, PDE75 |
1e-9 – 398 MeV |
Operational quantities |
Warning
NRB99_2009_effective covers a limited energy range (25 eV – 20 MeV).
Values outside this range are set to zero during interpolation.
from bssunfold import Detector, get_coefficients, interpolate_coefficients
# Set on Detector (affects all subsequent unfolds)
detector = Detector(cc_type="ICRP74_effective")
# Change after creation
detector.set_dose_coefficients("ICRP74_operational")
# Get coefficients directly for custom use
cc = get_coefficients("NRB99_2009_effective")
cc_interp = interpolate_coefficients(cc, detector.E_MeV)
Spectrum Comparison Metrics#
25 metrics organised into 7 categories. All implemented with pure NumPy/SciPy.
graph TD
A["Comparison Metrics"] --> B["Entropy"]
A --> C["Distribution"]
A --> D["Correlation"]
A --> E["Error"]
A --> F["Similarity"]
A --> G["Chi-squared"]
A --> H["Statistical"]
B --> B1["kl_divergence"]
B --> B2["cross_entropy"]
B --> B3["entropy_difference_percent"]
C --> C1["wasserstein_dist"]
C --> C2["energy_dist"]
C --> C3["kolmogorov_smirnov_stat"]
D --> D1["pearson_r"]
D --> D2["spearman_r"]
E --> E1["mean_squared_error"]
E --> E2["root_mean_squared_error"]
E --> E3["mean_absolute_error"]
E --> E4["mape"]
E --> E5["r2_score"]
E --> E6["max_error"]
E --> E7["median_absolute_error"]
F --> F1["cosine_similarity"]
F --> F2["mmd_rbf"]
G --> G1["chi_squared"]
G --> G2["g_test"]
G --> G3["freeman_tukey"]
G --> G4["cressie_read"]
H --> H1["anderson_darling"]
H --> H2["wilcoxon_test"]
H --> H3["mannwhitneyu_test"]
H --> H4["standardized_mean_difference"]
style A fill:#4a90d9,color:#fff
Metrics Reference#
Category |
Metric Key |
Description |
Range |
|---|---|---|---|
Entropy |
|
Kullback-Leibler divergence D_KL(p‖q) |
[0, ∞) |
|
Cross-entropy H(p,q) = -∑p·log(q) |
[0, ∞) |
|
|
Relative cross-entropy excess (%) |
[0, ∞) |
|
Distribution |
|
Earth mover’s / Wasserstein distance |
[0, ∞) |
|
Energy distance between distributions |
[0, ∞) |
|
|
Kolmogorov-Smirnov D-statistic |
[0, 1] |
|
Correlation |
|
Pearson correlation coefficient |
[-1, 1] |
|
Spearman rank correlation |
[-1, 1] |
|
Error |
|
Mean squared error |
[0, ∞) |
|
Root mean squared error |
[0, ∞) |
|
|
Mean absolute error |
[0, ∞) |
|
|
Mean absolute percentage error (%) |
[0, 100] |
|
|
R² (coefficient of determination) |
(-∞, 1] |
|
|
Maximum residual error |
[0, ∞) |
|
|
Median absolute error |
[0, ∞) |
|
Similarity |
|
Cosine similarity cos(θ) |
[0, 1] |
|
Maximum Mean Discrepancy (RBF kernel) |
[0, ∞) |
|
Chi-squared |
|
Pearson’s chi-squared statistic |
[0, ∞) |
|
G-test (log-likelihood ratio) |
[0, ∞) |
|
|
Freeman-Tukey statistic |
[0, ∞) |
|
|
Cressie-Read power divergence |
[0, ∞) |
|
Statistical |
|
Anderson-Darling k-sample statistic |
[0, ∞) |
|
Wilcoxon signed-rank test statistic |
[0, ∞) |
|
|
Mann-Whitney U test statistic |
[0, ∞) |
|
|
Cohen’s d (standardized mean difference) |
(-∞, ∞) |
Performance#
All iterative solvers use Numba JIT-compiled inner loops when numba is installed, with automatic fallback to pure Python.
Solver |
Before |
After |
Speedup |
|---|---|---|---|
Doroshenko |
40.6 ms |
0.8 ms |
50x |
Kaczmarz |
1.4 ms |
0.1 ms |
14x |
MLEM |
2.7 ms |
0.4 ms |
7x |
GRAVEL |
~2 ms |
0.6 ms |
3x |
cvxpy |
84 ms |
78 ms |
~1x (external solver) |
qpsolvers |
1.7 ms |
1.6 ms |
~1x (external solver) |
Install numba for the best performance:
pip install bssunfold[numba]
The JIT functions are defined in bssunfold.core._numba_jit and use
@njit(cache=True) for automatic disk caching of compiled code.