Detector Class#

class bssunfold.Detector(response_functions: DataFrame | dict | None = None, E_MeV: ndarray | None = None, sensitivities: dict | ndarray | None = None, cc_type: str = 'ICRP116')[source]#

Bases: object

Class for neutron detector operations and spectrum unfolding.

This class provides methods for neutron spectrum unfolding using various algorithms and includes tools for dose rate calculations based on ICRP-116 conversion coefficients.

Parameters:
  • response_functions (pd.DataFrame, dict, optional) – Response functions data. Can be: - pandas DataFrame with ‘E_MeV’ column and detector columns. - dict with ‘E_MeV’ key (array) and detector names as keys (arrays). If None, default GSF response functions are used.

  • E_MeV (np.ndarray, optional) – Energy grid in MeV. Required if response_functions is not provided and sensitivities is provided.

  • sensitivities (dict or np.ndarray, optional) – Detector sensitivities. If dict, keys are detector names and values are arrays of same length as E_MeV. If 2D array, shape (n_energy, n_detectors). Required if response_functions is not provided and E_MeV is provided.

Variables:
  • Amat (np.ndarray) – Response matrix with logarithmic energy step corrections

  • E_MeV (np.ndarray) – Energy grid in MeV

  • detector_names (List[str]) – Names of available detectors/spheres

  • log_steps (np.ndarray) – Logarithmic steps for each energy point

  • sensitivities (Dict[str, np.ndarray]) – Dictionary mapping detector names to their sensitivity arrays

  • cc_icrp116 (Dict[str, np.ndarray]) – Raw (non-interpolated) conversion coefficients for dose calculation

  • cc_type (str) – Name of the dose conversion coefficient dataset (default: “ICRP116”)

  • n_detectors (int) – Number of available detectors (property)

  • n_energy_bins (int) – Number of energy bins (property)

Examples

>>> from bssunfold import Detector
>>> # Create detector with default GSF response functions
>>> detector = Detector()
>>> # Perform unfolding
>>> readings = {'sphere_1': 100.5, 'sphere_2': 85.3}
>>> result = detector.unfold_cvxpy(readings)
__init__(response_functions: DataFrame | dict | None = None, E_MeV: ndarray | None = None, sensitivities: dict | ndarray | None = None, cc_type: str = 'ICRP116')[source]#

Initialize Detector with response functions.

Parameters:
  • response_functions (pd.DataFrame, dict, optional) – Response functions data.

  • E_MeV (np.ndarray, optional) – Energy grid in MeV.

  • sensitivities (dict or np.ndarray, optional) – Detector sensitivities.

  • cc_type (str, optional) – Name of the dose conversion coefficient dataset to use. Options: “ICRP116”, “ICRP74_effective”, “NRB99_2009_effective”, “ICRP74_operational”. Default: “ICRP116”.

Raises:
  • ValueError – If E_MeV is not a 1D array or has less than 2 energy points, or if input data is inconsistent.

  • TypeError – If response_functions has an unsupported type.

_process_input(response_functions: DataFrame | dict | None, E_MeV: ndarray | None, sensitivities: dict | ndarray | None) DataFrame[source]#

Convert various input formats to a unified DataFrame.

__str__() str[source]#

User-friendly string representation.

__repr__() str[source]#

Technical string representation.

__getattr__(name: str)[source]#

Provide helpful error for unrecognized unfold_* methods.

property n_detectors: int#

Number of available detectors.

property n_energy_bins: int#

Number of energy bins.

set_dose_coefficients(name: str) None[source]#

Change the dose conversion coefficient dataset.

Parameters:

name (str) –

Name of the coefficient dataset. Options:

  • "ICRP116": ICRP-116 effective dose (default)

  • "ICRP74_effective": ICRP-74 effective dose

  • "NRB99_2009_effective": NRB99-2009 effective dose

  • "ICRP74_operational": ICRP-74 operational quantities

Raises:

ValueError – If the coefficient name is not found.

Examples

>>> detector = Detector()
>>> detector.set_dose_coefficients("ICRP74_effective")
>>> detector.cc_type
'ICRP74_effective'
_get_interpolated_cc() dict[str, ndarray][source]#

Get conversion coefficients interpolated to this detector’s energy grid.

Returns:

Interpolated conversion coefficients on self.E_MeV.

Return type:

Dict[str, np.ndarray]

_validate_readings(readings: dict[str, float]) dict[str, float][source]#

Validate detector readings.

_build_system(readings: dict[str, float]) tuple[ndarray, ndarray, list[str]][source]#

Build response matrix A and measurement vector b.

_standardize_output(spectrum: ndarray, A: ndarray, b: ndarray, selected: list[str], method: str, **kwargs) dict[str, Any][source]#

Create standardized output dictionary.

_convert_rf_to_matrix_variable_step(rf_df: DataFrame, Emin: float = 1e-09) tuple[ndarray, ndarray, list[str], ndarray][source]#

Convert response functions to matrix with variable step correction.

_save_result(result: dict[str, Any]) str[source]#

Save unfolding result to history.

get_result(key: str | None = None) dict[str, Any] | None[source]#

Get unfolding result from history.

list_results() list[str][source]#

List all saved result keys.

clear_results() None[source]#

Clear all saved results.

_normalize_initial_spectrum(initial_spectrum: ndarray | dict | DataFrame | None) ndarray | None[source]#

Normalize initial spectrum to detector’s energy grid.

_cosine_similarity(spectrum1: ndarray, spectrum2: ndarray) float[source]#

Compute cosine similarity between two spectra.

_add_noise(readings: dict[str, float], noise_level: float = 0.01, random_state: int | None = None) dict[str, float][source]#

Add Gaussian noise to readings.

Parameters:
  • readings (Dict[str, float]) – Original readings.

  • noise_level (float, optional) – Relative noise level (default: 0.01).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Noisy readings.

Return type:

Dict[str, float]

_max_energy_mask(max_neutron_energy: float | None) ndarray[source]#

Boolean mask of energy bins with E_MeV <= max_neutron_energy.

Returns an all-True mask when max_neutron_energy is None (i.e. no upper cutoff is applied and the full grid is used).

_subdetector(mask: ndarray) Detector[source]#

Return a new Detector restricted to the bins selected by mask.

_expand_result(result: dict[str, Any], mask: ndarray, readings: dict[str, float]) dict[str, Any][source]#

Expand a reduced-grid unfolding result back to the full energy grid.

Bins excluded by mask (i.e. E_MeV > max_neutron_energy) are set to zero. Dose rates, effective readings and the residual are recomputed on the full grid so that all downstream quantities stay consistent. When mask is all True (no cutoff) the result is left unchanged apart from a consistent recomputation of the derived quantities.

unfold_cvxpy(readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0001, norm: int = 2, solver: str = 'default', calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, regularization_method: str = 'manual', noise_var: float | None = None, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using convex optimization (cvxpy).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • regularization (float, optional) – Regularization parameter (default: 1e-4).

  • norm (int, optional) – Norm type (1 for L1, 2 for L2), default: 2.

  • solver (str, optional) – Solver to use (‘ECOS’ or ‘default’).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • regularization_method (str, optional) – Method for selecting regularization parameter.

  • noise_var (float, optional) – Noise variance for discrepancy principle.

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_landweber(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 1000, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using Landweber iteration method.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum iterations (default: 1000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_mlem(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 1000, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using MLEM algorithm.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum iterations (default: 1000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_amg(readings: dict[str, float], initial_spectrum: ndarray | None = None, method: str = 'cg', preconditioner: str = 'amg', omega: float = 1.0, max_iterations: int = 200, tolerance: float = 1e-10, outer_iterations: int = 3, nonnegativity: bool = True, regularization: float | None = None, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using AMG/stationary-preconditioned Krylov iteration.

Python analogue of the Rlinsolve iterative-solver family and of algebraic multigrid preconditioning: the normal equations of the least-squares unfolding problem are solved with cg/bicgstab/gmres accelerated by a preconditioner approximating (A^T A)^-1 – algebraic multigrid (optional pyamg dependency) or one sweep of a classical stationary iteration (Jacobi, Gauss-Seidel, SOR, SSOR). Non-negativity is enforced with projected outer restarts.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial guess for the Krylov iteration.

  • method (str, optional) – Krylov solver: "cg" (default), "bicgstab" or "gmres".

  • preconditioner (str, optional) – "amg" (default), "jacobi", "gs", "sor", "ssor" or "none". "amg" falls back to Jacobi with a warning when pyamg is not installed.

  • omega (float, optional) – Relaxation factor for SOR/SSOR (default: 1.0).

  • max_iterations (int, optional) – Maximum Krylov iterations per restart (default: 200).

  • tolerance (float, optional) – Relative residual tolerance (default: 1e-10).

  • outer_iterations (int, optional) – Number of projected non-negativity restarts (default: 3).

  • nonnegativity (bool, optional) – Clamp between restarts (default: True).

  • regularization (float or None, optional) – Tikhonov damping for the normal equations; None (default) selects 1e-4 * mean(diag(A^T A)) automatically, 0.0 disables the damping.

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Relative noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_pspline_reml(readings: dict[str, float], initial_spectrum: ndarray | None = None, n_basis: int | None = None, spline_order: int = 4, diff_order: int = 2, knot_spacing: str = 'auto', weights: str | ndarray | None = 'uniform', lam_relative: float | None = None, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using P-spline mixed-model REML smoothing selection.

Python analogue of the R package LMMsolver (Boer 2023): the spectrum is represented as a P-spline, the spline coefficients are split into an unpenalised fixed part (polynomial trend, the null space of the difference penalty) and a penalised random part (the range space), and the smoothing parameter is the variance ratio estimated by maximising the REML profile likelihood of the resulting linear mixed model. The Henderson mixed model equations are then solved for the final spectrum.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Unused (kept for API compatibility).

  • n_basis (Optional[int], optional) – Dimension of the B-spline space (default: min(n//2, 30)).

  • spline_order (int, optional) – B-spline order (default: 4, cubic).

  • diff_order (int, optional) – Difference order of the P-spline penalty (default: 2).

  • knot_spacing (str, optional) – Interior knot placement: "auto" (default), "uniform" or "log".

  • weights (str or np.ndarray, optional) – "uniform" (default), "poisson" (w_i = 1 / b_i) or an explicit positive weight array.

  • lam_relative (Optional[float], optional) – Fixed relative smoothing parameter; skips REML selection.

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Relative noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary with additional keys lam, lam_relative, reml_loglik, sigma2, ed and ed_norm.

Return type:

Dict[str, Any]

unfold_gee(readings: dict[str, float], initial_spectrum: ndarray | None = None, family: str = 'gaussian', corstr: str = 'exchangeable', regularization: float = 0.0001, max_iterations: int = 100, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold by generalized estimating equations (R gee port).

The detector spheres are treated as a correlated cluster of observations of the measurement vector b = A x; the GEE score equations A^T R(alpha)^{-1} (b - A x) - lam G x = 0 are solved by iterated reweighted least squares with an exchangeable / AR-1 working correlation, and robust Liang-Zeger sandwich uncertainties are reported for the spectrum.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (used as starting point).

  • family (str, optional) – Quasi-likelihood family: "gaussian" (default), "poisson" or "gamma".

  • corstr (str, optional) – Working correlation: "exchangeable" (default), "ar1" or "independence".

  • regularization (float, optional) – Relative ridge on the second-difference roughness penalty (default: 1e-4).

  • max_iterations (int, optional) – Maximum GEE iterations (default: 100).

  • tolerance (float, optional) – Relative convergence tolerance (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Relative noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary with additional keys alpha, phi, family, corstr, robust_se, naive_se, spectrum_uncert_robust, pearson_chi2 and gee_converged.

Return type:

Dict[str, Any]

unfold_uno(readings: dict[str, float], initial_spectrum: ndarray | None = None, preset: str = 'filter_sqp', weights: str | ndarray | None = 'uniform', regularization: float = 0.001, hessian: str = 'exact', max_iterations: int = 300, tolerance: float = 1e-10, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold with an Uno-style Lagrange-Newton NLP preset.

Python analogue of the R package Uno (Vanaret & Leyffer 2024): the unfolding problem is solved as the constrained non-linear program min 1/2||W(Ax-b)||^2 + lam/2||D2 x||^2 s.t. x >= 0 either by the filterSQP preset (exact Hessian, filter globalisation; the convex objective is solved exactly in one QP sub-problem) or by the IPOPT-like primal-dual interior-point method (exact or BFGS Hessian).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (interior-point start).

  • preset (str, optional) – "filter_sqp" (default) or "ipopt_like".

  • weights (str or np.ndarray, optional) – "uniform" (default), "poisson" or an explicit array.

  • regularization (float, optional) – Relative roughness ridge (default: 1e-3).

  • hessian (str, optional) – "exact" (default) or "bfgs" (interior-point preset).

  • max_iterations (int, optional) – Maximum iterations (default: 300).

  • tolerance (float, optional) – KKT tolerance (default: 1e-10).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Relative noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary with additional keys uno_preset, objective, constraint_violation, dual_infeasibility and uno_converged.

Return type:

Dict[str, Any]

unfold_qpsolvers(readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0001, norm: int = 2, solver: str = 'osqp', calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, regularization_method: str = 'manual', noise_var: float | None = None, smoothness_order: int = 0, smoothness_weight: float = 1.0, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using qpsolvers with regularization selection.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess.

  • regularization (float, optional) – Regularization parameter, default: 1e-4.

  • norm (int, optional) – Norm type (1 for L1, 2 for L2), default: 2.

  • solver (str, optional) – QP solver name, default: ‘osqp’.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default: False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default: 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default: 100.

  • save_result (bool, optional) – Save result to history, default: False.

  • regularization_method (str, optional) – Method for selecting regularization parameter. Options: ‘manual’, ‘cosine’, ‘gcv’, ‘lcurve’, ‘dp’.

  • noise_var (float, optional) – Noise variance for discrepancy principle (‘dp’ method).

  • smoothness_order (int, optional) – Smoothness constraint order (0, 1, or 2), default: 0.

  • smoothness_weight (float, optional) – Weight for smoothness term, default: 1.0.

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

Dict[str, Any]

unfold_nnqp(readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0001, smoothness_order: int = 0, smoothness_weight: float = 1.0, tol: float = 1e-06, max_iterations: int = 10000, floor: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using NNQP (non-negative QP by coordinate descent).

Solves min 0.5 ||A x - b||^2 + alpha/2 ||L x||^2 + alpha0/2 ||x||^2 subject to x >= 0 using the NNQP coordinate-descent solver of Giovannucci & Pehlevan (simonsfoundation/NNQP).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Warm-start spectrum. If None, the NNQP solver uses a uniform random initial guess.

  • regularization (float, optional) – Tikhonov / smoothness regularization weight, default 1e-4.

  • smoothness_order (int, optional) – Smoothness penalty order (0, 1 or 2), default 0.

  • smoothness_weight (float, optional) – Weight for the smoothness term, default 1.0.

  • tol (float, optional) – Convergence tolerance, default 1e-6.

  • max_iterations (int, optional) – Iteration cap, default 10 000.

  • floor (float, optional) – Diagonal regularization floor added to Q to guarantee strict positive-definiteness, default 1e-6.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default 100.

  • save_result (bool, optional) – Save result to history, default False.

  • random_state (int, optional) – Random seed for reproducibility.

  • max_neutron_energy (float, optional) – Truncate the energy grid above this value (MeV).

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

Dict[str, Any]

unfold_qpmad(readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0001, smoothness_order: int = 0, smoothness_weight: float = 1.0, floor: float = 1e-06, lb: ndarray | None = None, ub: ndarray | None = None, backend: str = 'python', tol: float = 1e-09, max_iterations: int = 10000, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using qpmad (Goldfarb-Idnani dual active-set QP).

Solves min 0.5 ||A x - b||^2 + alpha/2 ||L x||^2 + alpha0/2 ||x||^2 subject to lb <= x <= ub (default: x >= 0) using the qpmad algorithm of Sherikov (asherikov/qpmad).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Accepted for API compatibility (Goldfarb-Idnani starts from the unconstrained minimum, not from x0).

  • regularization (float, optional) – Tikhonov / smoothness regularization weight, default 1e-4.

  • smoothness_order (int, optional) – Smoothness penalty order (0, 1 or 2), default 0.

  • smoothness_weight (float, optional) – Weight for the smoothness term, default 1.0.

  • floor (float, optional) – Diagonal regularization floor added to H to guarantee strict positive-definiteness, default 1e-6.

  • lb (np.ndarray, optional) – Simple bounds on the spectrum. If both are None (default) the method enforces x >= 0.

  • ub (np.ndarray, optional) – Simple bounds on the spectrum. If both are None (default) the method enforces x >= 0.

  • backend (str, optional) – ‘python’ (default) uses a pure-NumPy port of Goldfarb-Idnani; ‘qpmad’ calls the upstream C++ library if available.

  • tol (float, optional) – Numerical tolerance, default 1e-9.

  • max_iterations (int, optional) – Iteration cap for the Python backend, default 10 000.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default 100.

  • save_result (bool, optional) – Save result to history, default False.

  • random_state (int, optional) – Random seed for reproducibility.

  • max_neutron_energy (float, optional) – Truncate the energy grid above this value (MeV).

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

Dict[str, Any]

unfold_mystic(readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0001, norm: int = 2, solver: str = 'fmin_powell', maxiter: int | None = 2000, maxfun: int | None = 20000, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, regularization_method: str = 'manual', noise_var: float | None = None, smoothness_order: int = 0, smoothness_weight: float = 1.0, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using mystic with regularization selection.

Solves min ||A x - b||^2 + alpha * ||x||_norm subject to x >= 0 with the constrained-optimization framework mystic.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess.

  • regularization (float, optional) – Regularization parameter, default: 1e-4.

  • norm (int, optional) – Norm type (1 for L1, 2 for L2), default: 2.

  • solver (str, optional) – Mystic solver name: ‘fmin’, ‘fmin_powell’, ‘diffev’ or ‘diffev2’, default: ‘fmin_powell’.

  • maxiter (int, optional) – Maximum number of solver iterations, default: 2000.

  • maxfun (int, optional) – Maximum number of function evaluations, default: 20000.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default: False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default: 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default: 100.

  • save_result (bool, optional) – Save result to history, default: False.

  • regularization_method (str, optional) – Method for selecting regularization parameter. Options: ‘manual’, ‘cosine’, ‘gcv’, ‘lcurve’, ‘dp’.

  • noise_var (float, optional) – Noise variance for discrepancy principle (‘dp’ method).

  • smoothness_order (int, optional) – Smoothness constraint order (0, 1, or 2), default: 0.

  • smoothness_weight (float, optional) – Weight for smoothness term, default: 1.0.

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

Dict[str, Any]

unfold_mystic_hybrid(readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0001, norm: int = 2, global_solver: str = 'diffev2', local_solver: str = 'fmin_powell', global_maxiter: int | None = None, global_maxfun: int | None = None, local_maxiter: int | None = None, local_maxfun: int | None = None, npop: int | None = None, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, regularization_method: str = 'manual', noise_var: float | None = None, smoothness_order: int = 0, smoothness_weight: float = 1.0, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Two-stage hybrid unfolding: global search + local refinement.

Stage 1 uses a population-based solver (diffev2 by default) with automatically derived bounds to robustly locate the basin of the global minimum. Stage 2 feeds that result as x0 into a local direct-search solver (fmin_powell by default) for precise final convergence.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess for the global stage.

  • regularization (float, optional) – Regularization parameter, default: 1e-4.

  • norm (int, optional) – Norm type (1 for L1, 2 for L2), default: 2.

  • global_solver (str, optional) – Population-based solver for stage 1 ('diffev' or 'diffev2'), default: 'diffev2'.

  • local_solver (str, optional) – Local solver for stage 2 ('fmin' or 'fmin_powell'), default: 'fmin_powell'.

  • global_maxiter (int, optional) – Maximum iterations for the global stage (default: 200).

  • global_maxfun (int, optional) – Maximum function evaluations for the global stage.

  • local_maxiter (int, optional) – Maximum iterations for the local stage (default: 2000).

  • local_maxfun (int, optional) – Maximum function evaluations for the local stage.

  • npop (int, optional) – Population size for the global stage.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default: False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default: 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default: 100.

  • save_result (bool, optional) – Save result to history, default: False.

  • regularization_method (str, optional) – Method for selecting regularization parameter. Options: ‘manual’, ‘cosine’, ‘gcv’, ‘lcurve’, ‘dp’.

  • noise_var (float, optional) – Noise variance for discrepancy principle (‘dp’ method).

  • smoothness_order (int, optional) – Smoothness constraint order (0, 1, or 2), default: 0.

  • smoothness_weight (float, optional) – Weight for smoothness term, default: 1.0.

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

Dict[str, Any]

unfold_genetic(readings: dict[str, float], initial_spectrum: ndarray | None = None, solver: str = 'pso', epoch: int = 500, pop_size: int = 50, regularization: float = 0.01, norm: int = 2, smoothness_order: int = 2, smoothness_weight: float = 1.0, entropy_weight: float = 0.0, n_runs: int = 1, early_stop: int | None = None, half_range: float = 2.0, two_step: bool = False, n_coarse: int | None = None, smoother: str = 'none', sigma_smooth: float = 2.0, crossover: str = 'single', mutation: str = 'random', pareto_select: str = 'knee', calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, verbose: bool = False, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using a meta-heuristic (evolutionary) algorithm.

The optimizer searches in log space seeded with a Landweber warm-start solution (or the provided initial_spectrum), bounded to log(seed) +/- half_range decades, with a scale-consistent objective. Inspired by the genetic / PSO unfolding works of Shahabinejad & Sohrabpour (2017), Suman & Sarkar (2012), Woo et al. (2019) and Mukherjee (2004).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess. If None, a Landweber warm-start solution is used to seed the population.

  • solver (str, optional) – Meta-heuristic algorithm: ‘pso’, ‘ga’, ‘de’, ‘es’, ‘ep’, ‘abc’, ‘gwo’, ‘cmaes’ or ‘nsga2’, default: ‘pso’.

  • epoch (int, optional) – Maximum number of generations, default: 500.

  • pop_size (int, optional) – Population size, default: 50.

  • regularization (float, optional) – Tikhonov regularization weight, default: 1e-2.

  • norm (int, optional) – Norm for the regularization term (1 or 2), default: 2.

  • smoothness_order (int, optional) – Smoothness constraint order (0, 1, or 2), default: 2.

  • smoothness_weight (float, optional) – Weight for the smoothness term, default: 1.0.

  • entropy_weight (float, optional) – Weight of the negative Shannon-entropy objective (0 disables it).

  • n_runs (int, optional) – Number of independent runs whose results are averaged, default: 1. Not used by the ‘nsga2’ solver.

  • early_stop (int, optional) – Stop if the global best does not improve for this many consecutive epochs.

  • half_range (float, optional) – Half-width of the log-space search bounds in decades around the seed, default: 2.0.

  • two_step (bool, optional) – Run the two-step genetic scheme (TGASU-style): a coarse first step seeds the full-resolution population, default: False.

  • n_coarse (int, optional) – Number of coarse bins for two_step mode (default: None, i.e. max(8, n // 4)).

  • smoother (str, optional) – Post-processing smoother: ‘none’, ‘gaussian’, ‘mbc’, ‘gaussian_mbc’ or ‘second_difference’, default: ‘none’.

  • sigma_smooth (float, optional) – Gaussian filter sigma for the smoothers, default: 2.0.

  • crossover (str, optional) – GA crossover operator: ‘single’ or ‘arithmetic’ (TGASU); used by the numpy GA engine, default: ‘single’.

  • mutation (str, optional) – GA mutation operator: ‘random’ or ‘iterative’ (TGASU, decreasing step); used by the numpy GA engine, default: ‘random’.

  • pareto_select (str, optional) – Selection from the Pareto front for the ‘nsga2’ solver: ‘knee’, ‘min_residual’ or ‘max_entropy’, default: ‘knee’.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default: False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default: 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default: 100.

  • save_result (bool, optional) – Save result to history, default: False.

  • random_state (int, optional) – Random seed for reproducibility.

  • verbose (bool, optional) – If True, print the MEALPY optimization progress.

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

Dict[str, Any]

unfold_gnowee(readings: dict[str, float], initial_spectrum: ndarray | None = None, population: int = 25, max_gens: int = 200, max_fevals: int = 5000, stall_limit: int = 200, conv_tol: float = 1e-06, opt_conv_tol: float = 0.01, frac_elite: float = 0.2, frac_levy: float = 1.0, frac_mutation: float = 0.2, alpha_levy: float = 1.5, gamma_levy: float = 1.0, n_levy: int = 1, scaling_factor: float = 10.0, init_sampling: str = 'lhc', regularization: float = 0.01, norm: int = 2, smoothness_order: int = 2, smoothness_weight: float = 1.0, entropy_weight: float = 0.0, half_range: float = 2.0, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, verbose: bool = False, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using the Gnowee hybrid metaheuristic optimizer.

Gnowee (Bevins & Parsons, SlaybaughLab/Gnowee) combines Lévy flights (Cuckoo Search), golden-ratio crossover (Modified Cuckoo Search), scatter search (Egea 2009) and differential-evolution mutation in an elitist population with Metropolis-Hastings acceptance and stall-driven restarts.

The optimizer searches in log space seeded with a Landweber warm-start solution (or the provided initial_spectrum), bounded to log(seed) ± half_range decades, with a scale-consistent objective combining the relative L2 residual, Tikhonov regularisation, second-difference smoothness and (optionally) negative Shannon entropy.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess. If None, a Landweber warm-start solution is used to seed the population.

  • population (int, optional) – Population size, default 25 (Gnowee’s recommended value).

  • max_gens (int, optional) – Maximum number of generations, default 200.

  • max_fevals (int, optional) – Maximum fitness evaluations, default 5_000.

  • stall_limit (int, optional) – Stall-based termination threshold (evaluations), default 200.

  • conv_tol (float, optional) – Relative improvement tolerance for timeline extension, default 1e-6.

  • opt_conv_tol (float, optional) – Tolerance on the optimum value for fitness convergence, default 1e-2.

  • frac_elite (float, optional) – Elite fraction (crossover / scatter search), default 0.2.

  • frac_levy (float, optional) – Lévy flight fraction, default 1.0.

  • frac_mutation (float, optional) – Mutation discovery probability, default 0.2.

  • alpha_levy (float, optional) – Lévy exponent, default 1.5.

  • gamma_levy (float, optional) – Lévy scale, default 1.0.

  • n_levy (int, optional) – Number of independent Lévy samples, default 1.

  • scaling_factor (float, optional) – Lévy step length scale, default 10.0.

  • init_sampling (str, optional) – Initial sampler: 'lhc' or 'random', default 'lhc'.

  • regularization (float, optional) – Tikhonov regularisation weight, default 1e-2.

  • norm (int, optional) – Norm for the regularisation term (1 or 2), default 2.

  • smoothness_order (int, optional) – Smoothness penalty order (0, 1 or 2), default 2.

  • smoothness_weight (float, optional) – Weight for the smoothness term, default 1.0.

  • entropy_weight (float, optional) – Weight of the negative Shannon-entropy objective (0 disables it).

  • half_range (float, optional) – Half-width of the log-space search bounds in decades around the seed, default 2.0.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default 100.

  • save_result (bool, optional) – Save result to history, default False.

  • random_state (int, optional) – Random seed for reproducibility.

  • verbose (bool, optional) – Print Gnowee progress every 10 generations.

  • max_neutron_energy (float, optional) – Truncate the energy grid above this value (MeV).

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

Dict[str, Any]

unfold_smt(readings: dict[str, float], initial_spectrum: ndarray | None = None, nonneg: bool = True, timeout_ms: int = 10000, objective: str = 'l2', calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold a neutron spectrum using an SMT solver.

Minimizes ||A x - b||_2 and then the total fluence sum(x) over the non-negative orthant using the Z3 optimizer (z3-solver package, optional dependency). Falls back to the L1 residual on non-converging solves.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess (accepted for API compatibility).

  • nonneg (bool, optional) – Constrain the spectrum to be non-negative, default: True.

  • timeout_ms (int, optional) – SMT solver timeout in milliseconds, default: 10000.

  • objective (str, optional) – Residual objective: 'l2' (default) or 'l1'.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default: False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default: 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default: 100.

  • save_result (bool, optional) – Save result to history, default: False.

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

Dict[str, Any]

unfold_scip(readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0001, norm: int = 2, timeout: float = 10.0, smoothness_order: int = 0, smoothness_weight: float = 1.0, nonneg: bool = True, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, regularization_method: str = 'manual', noise_var: float | None = None, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold a neutron spectrum using the SCIP optimizer.

Minimizes the Tikhonov-regularized least-squares objective 0.5 * ||A x - b||^2 + penalty(x) with the SCIP Optimization Suite (pyscipopt package, optional dependency).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess, used as a warm start.

  • regularization (float, optional) – Regularization parameter, default: 1e-4.

  • norm (int, optional) – Norm type (1 for L1, 2 for L2), default: 2.

  • timeout (float, optional) – Time limit in seconds, default: 10.0.

  • smoothness_order (int, optional) – Smoothness constraint order (0, 1, or 2), default: 0.

  • smoothness_weight (float, optional) – Weight for the smoothness term, default: 1.0.

  • nonneg (bool, optional) – Constrain the spectrum to be non-negative, default: True.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default: False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default: 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default: 100.

  • save_result (bool, optional) – Save result to history, default: False.

  • regularization_method (str, optional) – Method for selecting the regularization parameter (‘manual’, ‘cosine’, ‘lcurve’, ‘gcv’, ‘dp’), default: ‘manual’.

  • noise_var (float, optional) – Noise variance for discrepancy principle (‘dp’ method).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

Dict[str, Any]

unfold_docplex(readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0001, norm: int = 2, timeout: float = 10.0, smoothness_order: int = 0, smoothness_weight: float = 1.0, nonneg: bool = True, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, regularization_method: str = 'manual', noise_var: float | None = None, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold a neutron spectrum using CPLEX (docplex).

Minimizes the Tikhonov-regularized least-squares objective 0.5 * ||A x - b||^2 + penalty(x) with IBM Decision Optimization CPLEX Modeling for Python (docplex + cplex packages, optional dependencies).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess (accepted for API compatibility).

  • regularization (float, optional) – Regularization parameter, default: 1e-4.

  • norm (int, optional) – Norm type (1 for L1, 2 for L2), default: 2.

  • timeout (float, optional) – Time limit in seconds, default: 10.0.

  • smoothness_order (int, optional) – Smoothness constraint order (0, 1, or 2), default: 0.

  • smoothness_weight (float, optional) – Weight for the smoothness term, default: 1.0.

  • nonneg (bool, optional) – Constrain the spectrum to be non-negative, default: True.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default: False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default: 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default: 100.

  • save_result (bool, optional) – Save result to history, default: False.

  • regularization_method (str, optional) – Method for selecting the regularization parameter (‘manual’, ‘cosine’, ‘lcurve’, ‘gcv’, ‘dp’), default: ‘manual’.

  • noise_var (float, optional) – Noise variance for discrepancy principle (‘dp’ method).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

Dict[str, Any]

unfold_cs(readings: dict[str, float], initial_spectrum: ndarray | None = None, n_atoms: int | None = None, sparsity: int | None = None, dictionary: ndarray | None = None, n_dictionary_iterations: int = 20, sigma_min: float = 0.01, sigma_decrease_factor: float = 0.5, mu_0: float = 1.0, L: int = 3, max_iterations: int = 1000, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Compressive Sensing (CS).

The spectrum is represented sparsely in a learned dictionary (K-SVD), sparse coding is performed with OMP, and reconstruction is done with the SL0 algorithm. This method is well suited for the highly underdetermined problem where the number of energy groups greatly exceeds the number of detector readings.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • n_atoms (int, optional) – Number of dictionary atoms.

  • sparsity (int, optional) – Target sparsity for dictionary learning.

  • dictionary (np.ndarray, optional) – Pre-learned dictionary (n x n_atoms).

  • n_dictionary_iterations (int, optional) – Number of K-SVD iterations (default: 20).

  • sigma_min (float, optional) – SL0 minimum sigma (default: 0.01).

  • sigma_decrease_factor (float, optional) – SL0 sigma decrease factor (default: 0.5).

  • mu_0 (float, optional) – SL0 step-size factor (default: 1.0).

  • L (int, optional) – SL0 inner iterations per sigma (default: 3).

  • max_iterations (int, optional) – SL0 maximum outer iterations (default: 1000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_nnksvd(readings: dict[str, float], initial_spectrum: ndarray | None = None, n_atoms: int = 15, sparsity: int = 2, dictionary: ndarray | None = None, training_signals: ndarray | None = None, n_dictionary_iterations: int = 80, lambda_tik: float = 0.01, prior_wt: float = 0.5, sparse_coder: str = 'nnls_topk', tolerance: float = 1e-06, n_nnls_iter: int | None = None, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Non-negative K-SVD (NN-KSVD).

Implements the BNCT epithermal neutron spectrum unfolding method of Xu et al. (NIMA 2026, https://doi.org/10.1016/j.nima.2026.172070). A non-negative dictionary is learned with non-negative K-SVD (non-negative truncation of dictionary atoms during the rank-1 SVD update), the spectrum is then represented as phi = D @ alpha where alpha is a non-negative K-sparse coefficient vector recovered on the equivalent (column-normalized) detection dictionary M_norm = normalize(R @ D).

Three sparse-coding strategies are supported:

  • "nnls_topk" (default, the article’s proposed method): global NNLS coarse solution → top-K atom screening → local NNLS fine optimization. Achieves ~0.97 correlation and ~12.5% relative flux error with the article’s optimal configuration (15 atoms, K=2).

  • "omp" — classic Orthogonal Matching Pursuit (greedy).

  • "nn_omp" — OMP with non-negativity constraint on the support LS step (solved as NNLS).

The reconstruction objective is a Tikhonov-regularized non-negative least-squares (Eq. 2.5/2.6 of the article) solved via augmented-matrix NNLS, with an optional training-sample prior constraint (prior_wt > 0).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. Used to seed training signals when no training_signals is supplied.

  • n_atoms (int, optional) – Number of dictionary atoms (default: 15, the article’s optimum).

  • sparsity (int, optional) – Target sparsity K (default: 2, the article’s optimum).

  • dictionary (np.ndarray, optional) – Pre-learned non-negative dictionary (n x n_atoms). Bypasses online K-SVD training.

  • training_signals (np.ndarray, optional) – Training signals for online K-SVD (n x m). If not provided, log-spaced Gaussian bumps on the energy grid are used.

  • n_dictionary_iterations (int, optional) – K-SVD iterations (default: 80, as in the article).

  • lambda_tik (float, optional) – Tikhonov smoothing regularization weight (default: 0.01).

  • prior_wt (float, optional) – Training-sample-driven prior weight (default: 0.5).

  • sparse_coder (str, optional) – Sparse-coding strategy: "nnls_topk", "omp" or "nn_omp" (default: "nnls_topk").

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

  • n_nnls_iter (int, optional) – Maximum NNLS iterations.

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • max_neutron_energy (float, optional) – Optional upper energy cutoff (MeV).

Returns:

Unfolding results dictionary with standard fields plus n_atoms, sparsity, sparse_coder, lambda_tik, prior_wt.

Return type:

Dict[str, Any]

unfold_reconst(readings: dict[str, float], initial_spectrum: ndarray | None = None, pp: float = 0.001, alpha: float = -1.0, beta: float = 0.0, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Turchin’s statistical regularization.

Pure numpy port of the RECONST.FOR algorithm (STREG1). Solves (B * beta + Omega * alpha) * f = A_vec * beta with automatic alpha/beta selection.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Ignored (for API compatibility).

  • pp (float, optional) – PP parameter for the smoothing matrix (default: 1e-3).

  • alpha (float, optional) – Regularization parameter. >0 fixed, <0 auto-select absolute value (default: -1).

  • beta (float, optional) – Data fidelity weight. >0 fixed, <=0 auto-select (default: 0).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_lmfit(readings: dict[str, float], initial_spectrum: ndarray | None = None, method: str = 'lbfgsb', model_name: str = 'elastic', regularization: float = 0.0001, regularization2: float = 0.0001, l1_weight: float = 0.5, regularization_method: str = 'manual', lambda_range: tuple[float, float] = (1e-06, 0.1), n_lambda: int = 30, verbose: bool = True, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using lmfit with L1/L2/Elastic regularization.

Parameters:
  • readings (Dict[str, float]) – Detector readings (counts or dose rates)

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • method (str, optional) – lmfit solver name (leastsq, lbfgsb, etc.), default: “lbfgsb”.

  • model_name (str, optional) – Regularization model: elastic, lasso, ridge, default: “elastic”.

  • regularization (float, optional) – L1 regularization strength, default: 1e-4.

  • regularization2 (float, optional) – L2 regularization strength for elastic net, default: 1e-4.

  • l1_weight (float, optional) – L1 weight for elastic net (0=pure L2, 1=pure L1), default: 0.5.

  • regularization_method (str, optional) – How to choose the regularization parameter. Options: ‘manual’ (use the supplied regularization/regularization2), or an information criterion ‘aic’, ‘aicc’ or ‘bic’. For non-manual selection the regularization parameter is swept over lambda_range and the candidate minimizing the chosen criterion is used. Default: ‘manual’.

  • lambda_range (Tuple[float, float], optional) – Log-spaced range of lambda candidates for information-criterion selection, default: (1e-6, 1e-1).

  • n_lambda (int, optional) – Number of lambda candidates for information-criterion selection, default: 30.

  • verbose (bool, optional) – Print the regularization selection summary, default: True.

  • calculate_errors (bool, optional) – Flag to calculate uncertainty via Monte-Carlo, default: False.

  • noise_level (float, optional) – Noise level for Monte-Carlo uncertainty calculation, default: 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples for error estimation, default: 100.

  • save_result (bool, optional) – If True, save result to internal history, default: False.

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Dictionary containing unfolding results.

Return type:

Dict[str, Any]

unfold_mlem_bs(readings: dict[str, float], initial_spectrum: ndarray | None = None, n_basis: int | None = None, spline_order: int = 4, beta: float | None = None, beta_relative: float | None = None, knot_spacing: str = 'auto', max_iterations: int = 1000, tolerance: float = 1e-06, auto_params: bool = False, bootstrap_ci: bool = False, n_bootstrap: int = 100, ci_alpha: float = 0.05, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using the B-spline MLEM method with regularization.

Implements the MLEM-BS algorithm of Mazankova et al. (CNDGS’2026, https://doi.org/10.47459/cndcgs.2026.61): the spectrum is represented as a non-negative combination of B-splines (B-spline sieve, Szkutik 2005) and the coefficients are found with the regularized MLEM iteration (Eq. 4 of the paper) using the second-derivative penalty P(b) = ||D^(2) b||_2^2 (Eq. 5). The iteration count, the B-spline space dimension N_s and the penalty strength can be selected automatically by minimizing the K_S goodness-of-fit statistic (Eq. 6). Confidence intervals of the unfolded spectrum can be estimated with the Poisson bootstrap of Eqs. 7-9.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess; projected onto the non-negative B-spline sieve. A flat spectrum is used when None.

  • n_basis (Optional[int], optional) – Dimension N_s of the B-spline space (default: None selects max(spline_order + 1, min(n_bins // 2, 40))). The paper optimizes N_s via the first local minimum of K_S; enable auto_params to reproduce that.

  • spline_order (int, optional) – B-spline order p (degree p - 1); the paper uses p = 4 (cubic). Default: 4.

  • beta (Optional[float], optional) – Absolute penalty strength of Eq. 4 (problem-scale dependent; the paper uses 1.0e-17 for its counting setup).

  • beta_relative (Optional[float], optional) – Scale-aware penalty strength: effective beta = beta_relative * mean column sum of RB. Mutually exclusive with beta; default (both None) disables the penalty.

  • knot_spacing (str, optional) – Interior knot placement: "auto" (default; log knots for grids spanning more than two decades, uniform knots otherwise), "uniform" or "log".

  • max_iterations (int, optional) – Iteration budget (default: 1000).

  • tolerance (float, optional) – Relative coefficient-change convergence tolerance (default: 1e-6).

  • auto_params (bool, optional) – Select the iteration count, N_s and the penalty strength by minimizing K_S (Eq. 6), following the paper’s parameter-optimization procedure (default: False).

  • bootstrap_ci (bool, optional) – Estimate percentile confidence intervals with the Poisson bootstrap (Eqs. 7-9). Default: False.

  • n_bootstrap (int, optional) – Number of bootstrap replicates (default: 100).

  • ci_alpha (float, optional) – Significance level; 0.05 gives a 95% interval (default).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for the bootstrap resampling.

  • max_neutron_energy (Optional[float], optional) – Truncate the energy grid at this value (default: None).

Returns:

Unfolding results dictionary enriched with ks_history, ks_final, chi2_pearson, n_basis, spline_order, knot_spacing, interior_knots, beta_effective, beta_relative, coefficients and, when requested, auto_selection, ci_low and ci_high keys.

Return type:

Dict[str, Any]

unfold_mlem_odl(readings: dict[str, float], initial_spectrum: ndarray | None = None, tolerance: float = 1e-06, max_iterations: int = 1000, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using MLEM with ODL (Operator Discretization Library).

Requires the ‘odl’ package to be installed.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum approximation.

  • tolerance (float, optional) – Convergence tolerance. Default is 1e-6.

  • max_iterations (int, optional) – Maximum number of iterations. Default is 1000.

  • calculate_errors (bool, optional) – Flag for calculating restoration errors. Default is False.

  • noise_level (float, optional) – Noise level for error calculation. Default is 0.01.

  • n_montecarlo (int, optional) – Number of Monte Carlo samples for error calculation. Default is 100.

  • save_result (bool, optional) – If True, save result to internal history. Default is False.

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Dictionary containing the spectrum restoration results.

Return type:

Dict

unfold_imaxed(readings: dict[str, float], initial_spectrum: ndarray | None = None, sigma_factor: float = 0.1, max_iterations: int = 5000, tolerance: float = 1e-08, line_search_tol: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using the IMAXED algorithm (Wong 2024).

unfold_amaxed(readings: dict[str, float], initial_spectrum: ndarray | None = None, sigma_factor: float = 0.1, target_chi2: float | None = None, max_iterations: int = 5000, tolerance: float = 1e-08, line_search_tol: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using the AMAXED algorithm (Wong 2024).

unfold_amaxed_regularization(readings: dict[str, float], initial_spectrum: ndarray | None = None, sigma_factor: float = 0.1, tau: float = 1.0, max_iterations: int = 5000, tolerance: float = 1e-08, line_search_tol: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using the AMAXED-Regularization algorithm (Wong 2024).

unfold_odl_pdhg(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 100, tau: float | None = None, sigma: float | None = None, use_tv: bool = True, tv_weight: float = 0.1, nonnegativity: bool = True, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using the Primal-Dual Hybrid Gradient (PDHG) algorithm.

unfold_odl_douglas_rachford(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 100, use_tv: bool = True, tv_weight: float = 0.1, nonnegativity: bool = True, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using Douglas-Rachford splitting.

unfold_qubo(readings: dict[str, float], initial_spectrum: ndarray | None = None, n_bits: int = 6, max_value: float | None = None, regularization: float = 0.01, max_iterations: int = 1000, annealing_time: int = 1000, num_reads: int = 10, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 50, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using a QUBO formulation with quantum-inspired annealing.

unfold_zfit(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 100, use_mcmc: bool = False, n_samples: int = 1000, regularization: float = 0.1, smoothness_weight: float = 0.01, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using zfit Bayesian inference.

unfold_mlem_stop(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 15000, cps_crossover: float = 30000.0, j_threshold: float | None = None, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using MLEM-STOP with J-factor early stopping criterion.

Uses the modified MLEM-STOP method from Montgomery et al. (2020). The J-factor indicator (Bouallegue et al. 2013) is computed at each iteration: J = sum((meas - est)^2) / sum(est). The algorithm stops when J falls below the threshold (mean(measurements) / cps_crossover).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum iterations (default: 15000).

  • cps_crossover (float, optional) – Crossover CPS value for automatic J threshold (default: 30000).

  • j_threshold (float, optional) – Explicit J threshold. If None, computed from cps_crossover.

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_epic(readings: dict[str, float], initial_spectrum: ndarray | None = None, target_sigmas: ndarray | None = None, sigma_frac: float = 0.1, regularization_order: int = 1, non_neg: bool = True, noise_var: float | None = None, homogeneous_step: bool = True, regularize: dict[str, Any] | None = None, beta_shift_k: float = 0, beta_distance: float = 2, EPIC_bool: ndarray | None = None, V: ndarray | None = None, LSQpar: dict[str, Any] | None = None, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold a neutron spectrum using EPIC Tikhonov regularization.

Selects the prior variances of the regularization operator such that the a posteriori variances of the model parameters match the target sigmas (Equal Posterior Information Condition), then solves the weighted least squares problem. Port of the EPIC_LS method of Ortega-Culaciati et al. (2021), frortega/EPIC_LS.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess (unused by this method).

  • target_sigmas (np.ndarray, optional) – Target a posteriori standard deviations of the model parameters. If None, derived as sigma_frac times the magnitude of the naive least-squares solution.

  • sigma_frac (float, optional) – Fraction used to derive the default target sigmas, default: 0.1.

  • regularization_order (int, optional) – Regularization operator order: 0 (identity), 1 (first derivative, default) or 2 (second derivative).

  • non_neg (bool, optional) – Constrain the spectrum to be non-negative, default: True.

  • noise_var (float, optional) – Variance of the i.i.d. misfit errors used to build Cx, default: None (identity Cx).

  • homogeneous_step (bool, optional) – Run a preliminary homogeneous Ch search, default: True.

  • regularize (dict, optional) – If given (can be empty), damp the EPIC weights towards a minimum-norm solution.

  • beta_shift_k (float, optional) – Center shift for the beta bounds, default: 0.

  • beta_distance (float, optional) – Distance kept from the representability limit, default: 2.

  • EPIC_bool (np.ndarray, optional) – Boolean mask of which parameters are subject to the EPIC.

  • V (np.ndarray, optional) – Matrix mapping the searched betas to the regularization rows, beta = V @ y (shape (H.shape[0], len(y))).

  • LSQpar (dict, optional) – Tuning parameters for the nonlinear least-squares solver.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default: False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default: 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default: 100.

  • save_result (bool, optional) – Save result to history, default: False.

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

Dict[str, Any]

unfold_combined(readings: dict[str, float], pipeline: list[dict[str, Any]], calculate_errors: bool = False, verbose: bool = True, max_neutron_energy: float | None = None) dict[str, Any] | None[source]#

Combined unfolding method applying multiple methods sequentially.

Parameters:
  • readings (Dict[str, float]) – Detector readings

  • pipeline (List[Dict[str, Any]]) – List of methods for sequential application.

  • calculate_errors (bool, optional) – Flag to calculate errors for the last method.

  • verbose (bool, optional) – Flag to print debug information.

Returns:

Dictionary with unfolding results.

Return type:

Dict

unfold_cascade(readings: dict[str, float], cascade_stages: list[CascadeStage] | None = None, calculate_errors: bool = False, verbose: bool = True, save_result: bool = False, multi_resolution: bool = False, coarse_bins: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Cascade unfolding with sequential method refinement.

Applies unfolding methods in sequence; each stage may use the previous result as an initial guess, a prior/reference spectrum, or a regularization target, and the cascade may stop early when a stage reaches its quality threshold. With multi_resolution=True the first stage runs on a coarse energy grid and its prolongated solution seeds the fine-grid stages. See bssunfold.core.unfold_cascade.unfold_cascade().

unfold_composite(readings: dict[str, float], n_methods: int = 5, timeout_per_method: float = 30.0, save_result: bool = False, spectrum: ndarray | None = None, energy: ndarray | None = None, method_names: list[str] | None = None, ensemble_weights: dict[str, float] | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Adaptive ensemble of unfolding methods with confidence-weighted combination.

Classifies the unknown spectrum by hardness, runs a pool of suitable individual methods, and combines their results. See bssunfold.core.unfold_composite.unfold_composite().

unfold_binned(readings: dict[str, float], bin_lookup: dict[str, Any] | None = None, lookup_path: str | None = None, timeout_per_method: float = 30.0, save_result: bool = False, max_neutron_energy: float | None = None) dict[str, Any][source]#

Bin-wise adaptive unfolding: best method per energy bin.

For each of the 60 energy bins, selects the unfolding method that performed best in that bin during benchmarking, and assembles the final spectrum by picking the winning value at every bin.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • bin_lookup (dict, optional) – Pre-computed per-bin method ranking. If None, loaded from lookup_path (or the built-in default shipped with the package).

  • lookup_path (str, optional) – Path to a JSON lookup file. Ignored when bin_lookup is given.

  • timeout_per_method (float) – Wall-clock timeout per individual method (seconds).

  • save_result (bool) – Persist result to detector history.

  • max_neutron_energy (float, optional) – Upper cut-off for the energy grid.

Returns:

Standard bssunfold result dict with extra keys method_map, successful_methods, individual_spectra.

Return type:

dict

See also

unfold_composite

Confidence-weighted ensemble of methods.

unfold_interpret(readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0001, norm: int = 2, smoothness_order: int = 0, smoothness_weight: float = 1.0, enforce_norm: bool = False, norm_value: float = 1.0, regularization_method: str = 'manual', noise_var: float | None = None, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, tolerance: float = 1e-08, interpret_options: dict[str, Any] | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold a neutron spectrum and interpret the solution with pyoptexplain.

Solves the same unfolding QP as unfold_qpsolvers() through pyoptexplain and attaches an interpretation report. The returned dict is the standard bssunfold result with two extra keys:

  • report – Markdown interpretation report.

  • interpretation_metrics – JSON-friendly metrics dictionary.

  • interpretation_spectrum – interpreted (zeroed) spectrum.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess (used by the ‘cosine’ regularization method).

  • regularization (float, optional) – Regularization parameter (default: 1e-4).

  • norm (int, optional) – Penalty norm, 1 or 2 (default: 2).

  • smoothness_order (int, optional) – Smoothness derivative order, 0, 1 or 2 (default: 0).

  • smoothness_weight (float, optional) – Weight of the smoothness term (default: 1.0).

  • enforce_norm (bool, optional) – Add sum(x) == norm_value (default: False).

  • norm_value (float, optional) – Target total fluence (default: 1.0).

  • regularization_method (str, optional) – Method for selecting the regularization parameter.

  • noise_var (float, optional) – Noise variance for the discrepancy principle (‘dp’ method).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • tolerance (float, optional) – Solver feasibility/optimality tolerance (default: 1e-8). Relax it (e.g. 1e-5) if pyoptexplain’s backend reports iteration_limit.

  • interpret_options (dict, optional) – Extra keyword arguments forwarded to interpret_qp().

Returns:

Standardized unfolding result plus report and interpretation_metrics keys.

Return type:

Dict[str, Any]

interpret_result(readings: dict[str, float], alpha: float = 0.0001, norm: int = 2, smoothness_order: int = 0, smoothness_weight: float = 1.0, enforce_norm: bool = False, norm_value: float = 1.0, max_neutron_energy: float | None = None, **kwargs: Any) dict[str, Any][source]#

Interpret a set of detector readings without unfolding.

Builds the response matrix from readings and runs interpret_qp() directly, returning the report, metrics, tables and interpreted spectrum.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • alpha (float, optional) – Regularization parameter (default: 1e-4).

  • norm (int, optional) – Penalty norm, 1 or 2 (default: 2).

  • smoothness_order (int, optional) – Smoothness derivative order, 0, 1 or 2 (default: 0).

  • smoothness_weight (float, optional) – Weight of the smoothness term (default: 1.0).

  • enforce_norm (bool, optional) – Add sum(x) == norm_value (default: False).

  • norm_value (float, optional) – Target total fluence (default: 1.0).

  • max_neutron_energy (float, optional) – Maximum neutron energy (MeV). Bins with E_MeV > max_neutron_energy are excluded from the interpretation.

  • **kwargs – Extra keyword arguments forwarded to interpret_qp().

Returns:

Dictionary with report, metrics, tables and spectrum keys.

Return type:

Dict[str, Any]

discretize_spectra(spectra: DataFrame | dict) DataFrame[source]#

Interpolate spectra onto target energy grid.

get_effective_readings_for_spectra(spectra: DataFrame | dict) dict[str, float][source]#

Calculate effective readings for a given spectrum.

static _import_optional(module_name: str, purpose: str) Any[source]#

Import optional dependency with informative error message.

_save_figure(fig: Any, save_to: str | None = None, dpi: int = 300, bbox_inches: str = 'tight', **savefig_kwargs) None[source]#

Save figure to file with support for multiple formats.

unfold_doroshenko(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 1000, tolerance: float = 1e-06, regularization: float = 0.0, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the Doroshenko coordinate update method.

Parameters:
  • readings (Dict[str, float]) – Detector readings (counts or dose rates)

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, uniform spectrum is used

  • max_iterations (int, optional) – Maximum number of iterations, default: 1000

  • tolerance (float, optional) – Convergence tolerance for solution change, default: 1e-6

  • regularization (float, optional) – Regularization strength to prevent division by zero, default: 0.0

  • calculate_errors (bool, optional) – Flag to calculate uncertainty via Monte-Carlo, default: False

  • noise_level (float, optional) – Noise level for Monte-Carlo uncertainty calculation, default: 0.01

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples for error estimation, default: 100

  • save_result (bool, optional) – If True, save result to internal history, default: False

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Dictionary containing unfolding results.

Return type:

Dict[str, Any]

unfold_directed_divergence(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 200, tol_chi2: float = 1.0, tol_rel: float = 1e-06, relative_uncertainty: float = 0.05, smoothness_order: int = 0, smoothness_weight: float = 0.0, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold sphere readings with the directed-divergence iteration.

unfold_express(readings: dict[str, float], initial_spectrum: ndarray | None = None, n_groups: int = 6, interval_boundaries: ndarray | None = None, max_iterations: int = 3, tol_iteration: float = 0.05, relative_uncertainty: float = 0.05, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold sphere readings with the piecewise-exponential Express model.

unfold_kaczmarz(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 1000, omega: float = 1.0, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the Kaczmarz algorithm (ART).

Parameters:
  • readings (Dict[str, float]) – Detector readings (counts or dose rates)

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, zero spectrum is used

  • max_iterations (int, optional) – Maximum number of iterations, default: 1000

  • omega (float, optional) – Relaxation parameter (0 < omega <= 2), default: 1.0

  • tolerance (float, optional) – Convergence tolerance for solution change, default: 1e-6

  • calculate_errors (bool, optional) – Flag to calculate uncertainty via Monte-Carlo, default: False

  • noise_level (float, optional) – Noise level for Monte-Carlo uncertainty calculation, default: 0.01

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples for error estimation, default: 100

  • save_result (bool, optional) – If True, save result to internal history, default: False

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Dictionary containing unfolding results.

Return type:

Dict[str, Any]

unfold_randomized_kaczmarz(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 1000, omega: float = 1.0, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the Randomized Kaczmarz algorithm.

Row selection is probabilistic with probability proportional to the squared row norm, achieving faster convergence than the cyclic variant for ill-conditioned systems (Strohmer & Vershynin, 2009).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum number of iterations (default: 1000).

  • omega (float, optional) – Relaxation parameter (default: 1.0).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • max_neutron_energy (float, optional) – Maximum neutron energy cutoff.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_gravel(readings: dict[str, float], initial_spectrum: ndarray | None = None, tolerance: float = 1e-08, max_iterations: int = 1000, regularization: float = 0.0, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the GRAVEL algorithm.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, default initial spectrum is used.

  • tolerance (float, optional) – Convergence tolerance (default: 1e-8).

  • max_iterations (int, optional) – Maximum iterations (default: 1000).

  • regularization (float, optional) – Regularization parameter (default: 0.0).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_maxed(readings: dict[str, float], initial_spectrum: ndarray | None = None, sigma_factor: float = 0.01, max_iterations: int = 5000, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the MAXED algorithm.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Reference spectrum. If None, a flat reference is used.

  • sigma_factor (float, optional) – Relative measurement uncertainty (default: 0.01).

  • max_iterations (int, optional) – Maximum L-BFGS-B iterations (default: 5000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_tikhonov_legendre(readings: dict[str, float], initial_spectrum: ndarray | None = None, delta: float = 0.05, n_polynomials: int = 15, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Tikhonov regularization with Legendre basis.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Not used (provided for API consistency).

  • delta (float, optional) – Regularization parameter (default: 0.05).

  • n_polynomials (int, optional) – Number of Legendre polynomials (default: 15).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_bayes(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 4000, tolerance: float = 0.001, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Bayesian iterative unfolding (D’Agostini).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Prior spectrum. If None, uniform prior is used.

  • max_iterations (int, optional) – Maximum iterations (default: 4000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-3).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_bayes_spline_regularization(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 4000, tolerance: float = 0.001, spline_degree: int = 3, spline_smooth: float = 0.01, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Bayesian iterative unfolding with spline regularization.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Prior spectrum. If None, uniform prior is used.

  • max_iterations (int, optional) – Maximum iterations (default: 4000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-3).

  • spline_degree (int, optional) – Spline degree (default: 3).

  • spline_smooth (float, optional) – Spline smoothing parameter (default: 1e-2).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_statreg(readings: dict[str, float], initial_spectrum: ndarray | None = None, unfoldermethod: str = 'EmpiricalBayes', regularization: float | None = None, basis_name: str = 'CubicSplines', boundary: str | None = None, derivative_degree: int = 2, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Turchin’s method of statistical regularization.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • unfoldermethod (str, optional) – Regularization method: ‘EmpiricalBayes’ or ‘User’ (default: ‘EmpiricalBayes’).

  • regularization (float, optional) – Regularization parameter for ‘User’ method.

  • basis_name (str, optional) – Basis type (default: ‘CubicSplines’).

  • boundary (str, optional) – Boundary condition, None or ‘dirichlet’.

  • derivative_degree (int, optional) – Derivative degree (1, 2, 3), default: 2.

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_scipy_direct_method(readings: dict[str, float], initial_spectrum: ndarray | None = None, tolerance: float = 1e-08, max_iterations: int = 4000, method: str = 'cg', calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using scipy linear solvers.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • tolerance (float, optional) – Solver tolerance (default: 1e-8).

  • max_iterations (int, optional) – Maximum solver iterations (default: 4000).

  • method (str, optional) – Solver method: ‘cg’, ‘cgs’, ‘bicgstab’, ‘gmres’, etc. (default: ‘cg’).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_tsvd(readings: dict[str, float], initial_spectrum: ndarray | None = None, method: str = 'discrepancy', k: int | None = None, threshold: float | None = None, noise_level: float | None = None, svd_solver: str = 'full', calculate_errors: bool = False, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Truncated SVD (TSVD).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • method (str, optional) – K-selection method: ‘discrepancy’, ‘l_curve’, ‘gcv’, ‘energy’, ‘threshold_ratio’, ‘median_threshold’, ‘donoho’ (default: ‘discrepancy’).

  • k (int, optional) – Fixed number of singular values to keep.

  • threshold (float, optional) – Threshold ratio for singular value truncation.

  • noise_level (float, optional) – Noise level for discrepancy principle.

  • svd_solver (str, optional) – SVD backend: 'full' (dense LAPACK, default), 'arpack' (implicit restarted Lanczos, the rARPACK analogue) or 'propack' (Lanczos bidiagonalization, the R svd PROPACK analogue). The iterative backends are used when a fixed k is provided; automatic k-selection always uses the dense solver.

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_lanczos(readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization_method: str = 'gcv', max_iterations: int | None = None, regularization: float = 1e-08, noise_level: float | None = None, calculate_errors: bool = False, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the Lanczos-hybrid (Krylov) method.

Performs Golub-Kahan (Lanczos-type) bidiagonalization of the response matrix, building a sequence of Krylov subspaces. At each iteration a new approximation is obtained by solving the projected Tikhonov problem, with the regularization parameter selected automatically on the projected problem by Generalized Cross Validation (GCV). No a-priori spectrum is required.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (accepted for API compatibility).

  • regularization_method (str, optional) – Method for selecting the regularization parameter. Only 'gcv' is supported (default: ‘gcv’).

  • max_iterations (int, optional) – Maximum Krylov dimension. Defaults to min(n_detectors, n_energy_bins).

  • regularization (float, optional) – Fallback regularization parameter (default: 1e-8).

  • noise_level (float, optional) – Relative noise level used for discrepancy-principle early stopping.

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_cgls(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 100, tolerance: float = 1e-12, regularization: float = 0.0, smoothness_order: int = 0, noise_level: float | None = None, calculate_errors: bool = False, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the CGLS iterative method.

CGLS (Conjugate Gradient for Least Squares) solves the least squares problem min ||A x - b||^2 with a truncated-CG iteration, optionally regularized by a ||L x||^2 Tikhonov term and/or stopped early by the discrepancy principle. Nonnegativity is enforced by clamping at each iteration.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a zero vector is used (the CGLS iteration does not depend on the initial guess).

  • max_iterations (int, optional) – Maximum number of CG iterations (default: 100).

  • tolerance (float, optional) – Relative tolerance on the normal-equation residual (default: 1e-12).

  • regularization (float, optional) – Tikhonov regularization parameter for the ||L x||^2 term (default: 0.0 = no extra regularization).

  • smoothness_order (int, optional) – Order of the derivative matrix used as the regularization operator L (0 = identity, 1 = first derivative, 2 = second derivative). Ignored when regularization is 0.

  • noise_level (float, optional) – Relative noise level used for discrepancy-principle stopping.

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_gks(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int | None = None, smoothness_order: int = 2, regularization_method: str = 'gcv', regularization: float = 1e-08, noise_level: float | None = None, calculate_errors: bool = False, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the GKS Krylov-hybrid method.

GKS (Golub-Kahan hybrid) performs Lanczos-type bidiagonalization of the response matrix, building a Krylov subspace of modest dimension. At each iteration the regularized problem is projected onto the subspace and solved, with the regularization parameter chosen automatically on the projected problem by GCV, the discrepancy principle, or the L-curve.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (accepted for API compatibility).

  • max_iterations (int, optional) – Maximum Krylov dimension. Defaults to min(n_detectors, n_energy_bins).

  • smoothness_order (int, optional) – Order of the derivative matrix used for regularization (default: 2).

  • regularization_method (str, optional) – Method for selecting the regularization parameter: 'gcv', 'dp', 'lcurve' or 'manual' (default: ‘gcv’).

  • regularization (float, optional) – Fallback/manual regularization parameter (default: 1e-8).

  • noise_level (float, optional) – Relative noise level used by the discrepancy principle when regularization_method='dp'.

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_tikhonov_tv(readings: dict[str, float], initial_spectrum: ndarray | None = None, epsilon: float | None = None, mu: tuple[float, float, float] = (1.0, 1.0, 1.0), max_iterations: int = 100, type_: str = 'TT', beta: float = 1.0, zthr: float = 2.5, tolerance: float = 0.0001, noise_level: float | None = None, calculate_errors: bool = False, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum with noise-constrained Tikhonov-TV.

Solves min f(x) subject to ||A x - b||^2 = epsilon with the ADMM scheme of Gazzola & Gholami adapted to 1D spectra. The regularizer f is a blend of total variation on the first derivative and Tikhonov smoothing on the second derivative, with the balancing parameter beta either fixed or estimated adaptively.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (accepted for API compatibility).

  • epsilon (float, optional) – Estimate of the squared 2-norm of the noise. If None, derived from noise_level ((noise_level * ||b||)^2) or from the residuals of an unregularized least-squares solve.

  • mu (Tuple[float, float, float], optional) – Penalty parameters (mu1, mu2, mu3) (default: (1, 1, 1)).

  • max_iterations (int, optional) – Maximum number of ADMM iterations (default: 100).

  • type (str, optional) – Optimization problem: 'TT' (TV + Tikhonov), 'TV' (pure total variation) or 'T' (pure Tikhonov) (default: ‘TT’).

  • beta (float, optional) – Balancing parameter between TV and Tikhonov terms, or 'adapt' for adaptive estimation (default: 1.0).

  • zthr (float, optional) – Threshold for the adaptive beta estimation (default: 2.5).

  • tolerance (float, optional) – Stabilization stopping criterion (default: 1e-4).

  • noise_level (float, optional) – Relative noise level used to derive a default epsilon.

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_tikhonov_sobolev_dp(readings: dict[str, float], initial_spectrum: ndarray | None = None, noise_level: float = 0.02, delta: float | None = None, penalty: str = 'sobolev', alpha_range: tuple[float, float] = (1e-10, 10000000000.0), max_iter: int = 100, calculate_errors: bool = False, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using Tikhonov + generalized discrepancy (alfaFinder).

Python port of the energy-non-invariant apparatus-function method of Ogorodnikov (2024), sections 3 and 5 (alfaFinder()): Tikhonov regularization with the discrete Sobolev W_2^1 penalty (first-difference operator, the discrete analogue of the Euler equation A*A z + alpha (z - z'') = A* u), with the regularization parameter alpha* selected by the generalized discrepancy principle ||A z - b||^2 = delta^2 (root found by a bracketing + Brent scheme combining the bisection and chord/secant methods used in the article).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (accepted for API compatibility).

  • noise_level (float, optional) – Relative noise level used to derive delta (default: 0.02, the article’s 0-2 % range).

  • delta (float, optional) – Explicit RMS noise level; overrides noise_level.

  • penalty (str, optional) – Penalty operator: "sobolev" (first difference, default), "curvature" (second difference) or "identity" (ridge).

  • alpha_range (tuple, optional) – Search interval for the regularization parameter.

  • max_iter (int, optional) – Maximum number of root-finder iterations (default: 100).

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty (default: False).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • max_neutron_energy (float, optional) – Truncate the energy grid above this value (MeV).

Returns:

Unfolding results dictionary with additional keys alpha (selected regularization parameter), discrepancy_status (0 = root found, 1 = delta too small, 2 = delta too large), dp_converged and residual_sq.

Return type:

Dict[str, Any]

unfold_sandii(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 50, tolerance: float = 0.001, chi_fac: int = 1, relative_uncertainty: float = 0.1, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the SAND-II algorithm.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • max_iterations (int, optional) – Maximum number of iterations (default: 50).

  • tolerance (float, optional) – Maximum relative spectrum change used when chi_fac=0 (default: 1e-3).

  • chi_fac (int, optional) – Convergence criterion: 1 = chi-square based, 0 = maximum relative deviation based (default: 1).

  • relative_uncertainty (float, optional) – Relative measurement uncertainty for the chi-square criterion (default: 0.1).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_louhi(readings: dict[str, float], initial_spectrum: ndarray | None = None, smoothness: float = 1.0, smooth_order: int = 1, auto_smooth: bool = False, chi2_target: float | None = None, max_iterations: int = 500, tolerance: float = 1e-06, relative_uncertainty: float = 0.1, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, variance_reduction: str = 'none', save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the LOUHI78 algorithm.

Constrained weighted least squares with generalized smoothing (Routti & Sandberg 1980): the quadratic program

min chi2(phi) = ||(b - A phi) / sigma||^2
  • smoothness^2 * ||L (phi - phi0)||^2

is solved under non-negativity constraints by Hildreth’s iterative quadratic programming (the LSI step of LOUHI78). With auto_smooth=True the smoothing weight is adjusted by a nonlinear regression so that the data chi-square reaches its expected value (LOUHI’s nonlinear mode).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Default (a-priori) spectrum. If None, a flat spectrum is used.

  • smoothness (float, optional) – Smoothing weight lambda (default: 1.0).

  • smooth_order (int, optional) – Smoothing operator order: 0 (identity), 1 (first differences) or 2 (second differences); default 1.

  • auto_smooth (bool, optional) – Adjust the smoothing weight automatically (default: False).

  • chi2_target (Optional[float], optional) – Target data chi-square for auto_smooth (default: number of detectors).

  • max_iterations (int, optional) – Maximum number of Hildreth sweeps (default: 500).

  • tolerance (float, optional) – Relative objective change per sweep for convergence (default: 1e-6).

  • relative_uncertainty (float, optional) – Relative measurement uncertainty (default: 0.1).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • variance_reduction (str, optional) – MC variance reduction: ‘none’, ‘antithetic’, ‘control’, ‘both’ (default: ‘none’).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • max_neutron_energy (Optional[float], optional) – Restrict the energy grid to bins below this energy.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_crystal_ball(readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the CRYSTAL BALL algorithm.

CRYSTAL BALL is a direct (non-iterative) method that represents the spectrum as a linear combination of the detector response functions. This is an independent open-source reimplementation based on the published algorithmic description; the original code is proprietary.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Unused; accepted for interface uniformity.

  • regularization (float, optional) – Tikhonov regularization strength for the Gram-matrix inversion (default: 0.0).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_rfsp_jul(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 200, tolerance: float = 0.0001, weights: ndarray | None = None, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the RFSP-JUL algorithm.

RFSP-JUL is an iterative, damped least-squares method minimising a weighted residual functional with a Marquardt-style damping term that ties each iterate to the previous one. This is an independent open-source reimplementation based on the published description; the original code is proprietary.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • max_iterations (int, optional) – Maximum number of iterations (default: 200).

  • tolerance (float, optional) – Convergence tolerance on maximum relative spectrum change (default: 1e-4).

  • weights (np.ndarray, optional) – Per-detector weights for the residual term. None => equal weights.

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_ssr(readings: dict[str, float], initial_spectrum: ndarray | None = None, fn: str | int = 'auto', max_iterations: int = 500, tolerance: float = 1e-06, smooth_every: int = 1, inner_sweeps: int = 1, fn_ladder_cap: int = 8, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using SSR Sign-Simplicity-Regression (sisireg port).

Python port of the R package sisireg 1.2.1 (Metzner): MLEM data-fidelity steps alternate with non-equidistant SSR QSOR sweeps of the spectrum over the energy grid. Each sweep replaces interior bins by the simplicitic neighbour interpolation and reverts updates that would violate the partial sum criterion (threshold fn), which suppresses sign-inadequate wiggles. With fn="auto" the threshold is selected by the minimum statistic ladder: it starts at int(0.66 * partial_sum_quantile(n, k_run)) and decreases while the folded residuals stay sign-adequate (partial sum / maximum run test in the data space) and the spectrum does not gain extrema.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (flat start when missing).

  • fn (str or int, optional) – "auto" (default, minimum statistic ladder) or a fixed partial sum threshold.

  • max_iterations (int, optional) – Maximum number of outer MLEM + sweep iterations (default: 500).

  • tolerance (float, optional) – Relative L2 stopping tolerance (default: 1e-6).

  • smooth_every (int, optional) – Apply the SSR sweep every smooth_every-th iteration (default: 1).

  • inner_sweeps (int, optional) – Number of QSOR passes per SSR step (default: 1).

  • fn_ladder_cap (int, optional) – Maximum number of ladder candidates for fn="auto" (default: 8).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Relative noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary with additional keys fn, fn_start, k_run, n_extrema, ps_valid_data, run_valid_data and ssr_converged.

Return type:

Dict[str, Any]

unfold_staysl(readings: dict[str, float], initial_spectrum: ndarray | None = None, relative_uncertainty: float = 0.1, prior_uncertainty: float = 1.0, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the STAY’SL Bayesian algorithm.

STAY’SL is a single-step linear Bayesian least-squares update that refines a prior spectrum using the full measurement and prior covariance information. This is an independent open-source reimplementation based on the published mathematical formulation; the original code is proprietary.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Prior spectrum guess. If None, a flat spectrum is used as the prior mean.

  • relative_uncertainty (float, optional) – Relative measurement uncertainty for the covariance (default: 0.1).

  • prior_uncertainty (float, optional) – Relative prior uncertainty for the covariance (default: 1.0).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_bunki(readings: dict[str, float], initial_spectrum: ndarray | None = None, smoothing: float = 0.1, max_iterations: int = 1000, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the BUNKI (SPUNIT) algorithm.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • smoothing (float, optional) – Three-point smoothing factor (default: 0.1).

  • max_iterations (int, optional) – Maximum number of iterations (default: 1000).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_bunkiut(readings: dict[str, float], initial_spectrum: ndarray | None = None, smoothing: float = 0.05, max_iterations: int = 1000, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the BUNKI-UT (BON31G) algorithm.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • smoothing (float, optional) – Three-point smoothing factor (default: 0.05).

  • max_iterations (int, optional) – Maximum number of iterations (default: 1000).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_ferdor(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 100, tolerance: float = 0.001, smoothing: float = 0.001, chi_squared_target: float = 1.0, relative_uncertainty: float = 0.1, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the FERDOR algorithm.

FERDOR (ORNL; Burrus, ORNL-4154) is a constrained least-squares unfolding code with second-difference smoothing. The smoothing weight is adjusted iteratively so the reduced chi-square of the fit reaches chi_squared_target (discrepancy principle), and the final spectrum is non-negative.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • max_iterations (int, optional) – Maximum number of smoothing-weight iterations (default: 100).

  • tolerance (float, optional) – Relative tolerance on the reduced chi-square (default: 1e-3).

  • smoothing (float, optional) – Initial smoothing weight alpha (default: 1e-3).

  • chi_squared_target (float, optional) – Target reduced chi-square per degree of freedom (default: 1.0).

  • relative_uncertainty (float, optional) – Relative measurement uncertainty for the chi-square criterion (default: 0.1).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_rebunki(readings: dict[str, float], initial_spectrum: ndarray | None = None, smoothing: float = 0.1, max_iterations: int = 1000, tolerance: float = 0.01, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the ReBUNKI (SPUNIT) algorithm.

ReBUNKI (Lacerda et al., 2018) is a modern open reimplementation of the BUNKI code; its Python version supports the SPUNIT iterative algorithm. The default tolerance matches the ~1% relative-error convergence recommended by ReBUNKI.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • smoothing (float, optional) – Three-point smoothing factor (default: 0.1).

  • max_iterations (int, optional) – Maximum number of iterations (default: 1000).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 0.01).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_nsduaz(readings: dict[str, float], initial_spectrum: ndarray | None = None, catalogue: dict[str, ndarray] | None = None, use_catalogue: bool = True, reference_name: str | None = None, smoothing: float = 0.1, max_iterations: int = 1000, tolerance: float = 0.01, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the NSDUAZ algorithm.

NSDUAZ (Universidad Autonoma de Zacatecas; Ortiz-Rodriguez & Vega-Carrillo, 2012) uses the SPUNIT iterative algorithm with an initial spectrum selected from a catalogue of standard spectra by a statistical test on count-rate ratios relative to the reference (20.32 cm) sphere.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Explicit initial spectrum guess. When given, it overrides the catalogue selection.

  • catalogue (Optional[Dict[str, np.ndarray]], optional) – User-supplied catalogue of candidate initial spectra (label -> spectrum on the detector energy grid). When None, the built-in mini-catalogue is used.

  • use_catalogue (bool, optional) – If True (default), select the initial spectrum from the catalogue when initial_spectrum is not provided; if False, a flat spectrum is used.

  • reference_name (str, optional) – Reference sphere name for the catalogue test (default: auto-detect 20.32 cm sphere).

  • smoothing (float, optional) – Three-point smoothing factor (default: 0.1).

  • max_iterations (int, optional) – Maximum number of iterations (default: 1000).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 0.01).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_nspline(readings: dict[str, float], initial_spectrum: ndarray | None = None, knots: Any | None = None, continuity: str = 'C0C1', relative_uncertainty: float = 0.1, max_iterations: int = 200, tol: float = 0.001, step_theta: float = 0.1, smoothing: bool = True, n_segments: int | None = None, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the N-spline method (2008).

Implements Islamgulov & Lartsev (Atomic Energy 104(5), 295-302, 2008): the spectrum is parameterised by a “neutron” spline N(E) = exp(a + q ln E + r E) with C0/C1 continuity at the knots, and the activation equations are solved by the directed divergence (MIRD) minimisation loop with an N-spline smoothing at every iteration. The result includes the paper’s acceptability statistic nev (acceptable when nev <= 1 + 2/sqrt(N)).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess; the paper recommends a Monte-Carlo calculated spectrum. A flat spectrum is used when None.

  • knots (Optional[Any], optional) – N-spline knots: None (automatic log-uniform grid), a preset name from bssunfold.core.NSPLINE_KNOT_PRESETS (“BARS5_channel”, “IGRIK_channel”, “IGRIK_surface”, “YAGUAR_channel”) or an explicit increasing sequence (MeV).

  • continuity (str, optional) – Spline continuity: "C0C1" (default), "C0" or "none".

  • relative_uncertainty (float, optional) – Relative measurement uncertainty dQ/Q for the stopping criteria and the nev statistic (default: 0.1).

  • max_iterations (int, optional) – Iteration budget (default: 200).

  • tol (float, optional) – Relative H-decrease stopping tolerance (default: 1e-3).

  • step_theta (float, optional) – Conservative MIRD step factor (default: 0.1).

  • smoothing (bool, optional) – Per-iteration N-spline smoothing (default: True, as in the paper; False reduces the loop to the plain MIRD update).

  • n_segments (int, optional) – Number of spline segments when knots=None.

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • max_neutron_energy (Optional[float], optional) – Truncate the energy grid at this value (default: None).

Returns:

Unfolding results dictionary enriched with H, H_history, H_target, nev, nev_limit, acceptable, stop_reason, fluence, mean_energy, knots and knots_source keys.

Return type:

Dict[str, Any]

unfold_mcmc(readings: dict[str, float], initial_spectrum: ndarray | None = None, sigma_prior: float = 0.05, lambda_prior: float = 0.5, lengthscale: float = 3.0, n_samples: int = 2000, tune: int = 1000, chains: int = 2, target_accept: float = 0.95, use_hierarchical: bool = False, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, progressbar: bool = False, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Bayesian MCMC with NUTS sampler.

Full Bayesian unfolding with the No-U-Turn Sampler (NUTS). The method returns the mean posterior spectrum together with 95% HPD credible intervals, per-bin posterior standard deviations and convergence diagnostics (R-hat, effective sample size) under result['mcmc_stats'].

The spectrum is modelled on the log scale with a smoothness (Ornstein-Uhlenbeck) prior anchored on a data-driven center (the non-negative least-squares solution, or a user-supplied initial_spectrum), which keeps the underdetermined unfolding problem well posed for NUTS.

Requires optional pymc and arviz (pip install bssunfold[mcmc] or pip install pymc arviz).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Prior center guess for the spectrum. When None, the non-negative least-squares solution of A @ x = b is used as the prior center.

  • sigma_prior (float, optional) – Relative likelihood noise scale (default: 0.05). With use_hierarchical=False the noise is fixed at sigma_prior * |b|; with use_hierarchical=True it is the prior scale of the estimated relative noise.

  • lambda_prior (float, optional) – Prior scale of the log-spectrum spatial amplitude (default: 0.5).

  • lengthscale (float, optional) – OU smoothness correlation length in energy bins (default: 3.0).

  • n_samples (int, optional) – Number of MCMC samples per chain after tuning (default: 2000).

  • tune (int, optional) – Number of tuning (warmup) samples per chain (default: 1000).

  • chains (int, optional) – Number of independent MCMC chains (default: 2).

  • target_accept (float, optional) – Target acceptance rate for NUTS (default: 0.95).

  • use_hierarchical (bool, optional) – Estimate the likelihood noise from the data (default: False).

  • calculate_errors (bool, optional) – Calculate additional Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for additional Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of additional Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • progressbar (bool, optional) – Show sampling progress bar (default: False).

Returns:

Unfolding results dictionary. Includes the standard keys (energy, spectrum, effective_readings, residual, residual_norm, method, doserates) plus MCMC-specific keys spectrum_uncertainty, spectrum_lower, spectrum_upper and mcmc_stats.

Return type:

Dict[str, Any]

Raises:
  • ImportError – If PyMC or ArviZ is not installed.

  • RuntimeError – If MCMC sampling fails.

unfold_maeo(readings: dict[str, float], n_cycles: int = 20, n_gen_per_cycle: int = 10, pop_size: int = 100, algorithms: list[str] | None = None, lambda_smooth: float = 0.01, prior_spectrum: ndarray | None = None, initial_spectrum: ndarray | None = None, convergence_assist_ratio: float = 0.2, seed: int | None = None, verbose: bool = False, save_result: bool = False, max_neutron_energy: float | None = None, **kwargs) dict[str, Any][source]#

Unfold neutron spectrum using MAEO ensemble optimization.

This method implements the Multiobjective Animorphic Ensemble Optimization (MAEO) framework from Erdem et al. (2026), which combines multiple multiobjective optimization algorithms (NSGA-III, CTAEA, AGEMOEA2, SPEA2) in an ensemble with adaptive migration based on hypervolume performance.

The MAEO framework is particularly effective for neutron spectrum unfolding because it: - Handles multiple conflicting objectives (data fit vs. smoothness) - Automatically selects the best-performing algorithm for the problem - Provides robust convergence through ensemble diversity - Supports parallel evaluation of individuals

Parameters:
  • readings (dict) – Dictionary mapping detector names to measured count rates.

  • n_cycles (int, optional) – Number of MAEO cycles (default: 20). Each cycle runs n_gen_per_cycle generations for each island algorithm.

  • n_gen_per_cycle (int, optional) – Generations per cycle for each island (default: 10).

  • pop_size (int, optional) – Population size per island (default: 100).

  • algorithms (list of str, optional) – List of algorithm names to use as islands. Default uses the four algorithms from the MAEO paper: [“nsga3”, “ctaea”, “agemoea2”, “spea2”]. Available options: “nsga3”, “ctaea”, “agemoea2”, “spea2”.

  • lambda_smooth (float, optional) – Smoothness regularization weight (default: 0.01). Controls the trade-off between data fidelity and spectrum smoothness.

  • prior_spectrum (np.ndarray, optional) – Prior/guess spectrum for additional objective. If provided, adds a third objective to minimize deviation from this prior.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum for warm-start. Used to seed the population in log space.

  • convergence_assist_ratio (float, optional) – Fraction of cycles to dedicate to the best-performing island at the end (default: 0.2). Implements the “convergence assist” mechanism from MAEO.

  • seed (int, optional) – Random seed for reproducibility.

  • verbose (bool, optional) – Print progress information including hypervolume history (default: False).

  • save_result (bool, optional) – Save result to history (default: False).

  • **kwargs – Additional keyword arguments passed to the underlying optimizer.

Returns:

Standardized result dictionary containing:

  • ’energy’: Energy grid in MeV

  • ’spectrum’: Unfolded spectrum (non-negative)

  • ’spectrum_absolute’: Absolute flux values

  • ’effective_readings’: Computed readings from unfolded spectrum

  • ’residual’: Difference between measured and computed readings

  • ’residual_norm’: L2 norm of residual

  • ’method’: ‘MAEO’

  • ’doserates’: Dose rates calculated from spectrum

  • ’maeo_info’: Dictionary with MAEO-specific information:

    • ’n_cycles’: Number of cycles executed

    • ’best_algorithm’: Name of best-performing algorithm

    • ’hypervolume_history’: HV history for each island

    • ’population_history’: Population sizes per island per cycle

    • ’algorithms_used’: List of algorithms used

  • ’maeo_pareto_front’: Final Pareto front objectives (if available)

  • ’maeo_objectives’: Objectives for selected solution

Return type:

dict

Notes

The MAEO framework optimizes multiple objectives simultaneously:

  1. Minimize data fidelity error ||b - A*phi||^2 / ||b||^2

  2. Minimize spectrum roughness ||D2 * phi||^2 (second derivative)

  3. (Optional) Minimize deviation from prior spectrum

The final solution is selected from the combined Pareto front using a knee-point detection method to balance accuracy and smoothness.

The algorithm runs in two phases:

  1. Migration phase: All islands run in parallel, with individuals migrating toward better-performing islands based on hypervolume indicators.

  2. Convergence phase: Only the best-performing island continues, focusing computational resources on exploitation.

References

[1] O.F. Erdem, D. Price, P. Seurin, M.I. Radaideh, “MAEO: Multiobjective

Animorphic Ensemble Optimization for Scalable Large-scale Engineering Applications”, arXiv:2604.26973 (2026).

[2] D. Price, M.I. Radaideh, “Animorphic Ensemble Optimization: a large-scale

island model”, Neural Computing and Applications 35 (4) (2023) 3221-3243.

Examples

>>> from bssunfold import Detector
>>> detector = Detector()
>>> readings = {
...     'sphere_1': 100.5,
...     'sphere_2': 85.3,
...     'sphere_3': 72.1,
...     'sphere_4': 58.9,
...     'sphere_5': 45.2,
...     'sphere_6': 32.8,
... }
>>> # Run MAEO with default settings
>>> result = detector.unfold_maeo(readings, n_cycles=15)
>>> print(f"Spectrum integral: {np.sum(result['spectrum']):.2f}")
>>> print(f"Best algorithm: {result['maeo_info']['best_algorithm']}")
>>>
>>> # Run with custom algorithms and verbose output
>>> result = detector.unfold_maeo(
...     readings,
...     algorithms=["nsga3", "spea2"],
...     n_cycles=10,
...     verbose=True,
... )
unfold_osem(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 50, n_subsets: int = 1, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the OSEM algorithm.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • max_iterations (int, optional) – Maximum number of iterations (default: 50).

  • n_subsets (int, optional) – Number of ordered subsets over the detector readings (default: 1, i.e. standard MLEM).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_osem_anlm(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 50, n_subsets: int = 1, tolerance: float = 1e-06, h: float | None = None, search_window: int = 11, similarity_window: int = 3, alpha: float = 1.0, anlm_mode: str = 'subset', log_space: bool = True, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the OSEM-ANLM algorithm.

Ordered-subset expectation maximisation with asymptotic non-local means regularization (Jamaati et al. 2026, https://doi.org/10.1038/s41598-026-70607-1): the two-stage ANLM filter is applied to the intermediate spectrum after every OSEM subset update (anlm_mode='subset') or once to the OSEM result (anlm_mode='post').

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • max_iterations (int, optional) – Maximum number of iterations (default: 50).

  • n_subsets (int, optional) – Number of ordered subsets over the detector readings (default: 1, i.e. standard MLEM with per-iteration ANLM).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

  • h (float, optional) – Noise level for the ANLM filter (in log units when log_space=True). If None (default), it is estimated automatically from the intermediate spectra.

  • search_window (int, optional) – ANLM search window N (default: 11, article optimum).

  • similarity_window (int, optional) – ANLM similarity (patch) window nu (default: 3, article optimum).

  • alpha (float, optional) – Spread of the Gaussian kernel over the similarity window (default: 1.0).

  • anlm_mode (str, optional) – 'subset' — ANLM after every subset update (default, article pseudo-code); 'post' — single ANLM application to the OSEM result.

  • log_space (bool, optional) – Apply the ANLM filter to the logarithm of the spectrum (default: True, scale-free for spectra spanning orders of magnitude).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_mapem(readings: dict[str, float], initial_spectrum: ndarray | None = None, prior: str = 'quadratic', beta: float = 0.001, prior_delta: float = 1.0, gamma: float = 1.0, max_iterations: int = 50, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using penalised EM (MAP-EM).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • prior (str, optional) – Prior type: 'none', 'quadratic', 'logcosh' or 'relative_difference' (default: 'quadratic').

  • beta (float, optional) – Prior weight (default: 1e-3).

  • prior_delta (float, optional) – Width parameter of the quadratic/logcosh priors and additive floor of the relative-difference prior (default: 1.0).

  • gamma (float, optional) – Edge-preservation parameter of the relative-difference prior (default: 1.0).

  • max_iterations (int, optional) – Maximum number of iterations (default: 50).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_bsrem(readings: dict[str, float], initial_spectrum: ndarray | None = None, prior: str = 'none', beta: float = 0.001, prior_delta: float = 1.0, gamma: float = 1.0, max_iterations: int = 50, n_subsets: int = 1, tolerance: float = 1e-06, relaxation: float | Callable[[int], float] | None = None, addition_after_iteration: float = 0.0001, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the BSREM algorithm.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • prior (str, optional) – Prior type: 'none', 'quadratic', 'logcosh' or 'relative_difference' (default: 'none').

  • beta (float, optional) – Prior weight (default: 1e-3).

  • prior_delta (float, optional) – Width parameter of the quadratic/logcosh priors and additive floor of the relative-difference prior (default: 1.0).

  • gamma (float, optional) – Edge-preservation parameter of the relative-difference prior (default: 1.0).

  • max_iterations (int, optional) – Maximum number of iterations (default: 50).

  • n_subsets (int, optional) – Number of ordered subsets over the detector readings (default: 1).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

  • relaxation (float or callable, optional) – Relaxation sequence (default: None -> constant 1).

  • addition_after_iteration (float, optional) – Floor value for spectrum bins (default: 1e-4).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_sart(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 50, tolerance: float = 1e-06, relaxation: float | Callable[[int], float] | None = None, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the SART algorithm.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • max_iterations (int, optional) – Maximum number of iterations (default: 50).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

  • relaxation (float or callable, optional) – Relaxation sequence (default: None -> constant 0.8).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_fista(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 500, tolerance: float = 1e-08, regularization: float = 0.0, l1_penalty: float = 0.0, tv_penalty: float = 0.0, nonnegativity: bool = True, x_min: float = 0.0, x_max: float = inf, noise_level: float | None = None, eta: float = 1.01, calculate_errors: bool = False, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using FISTA algorithm.

The Fast Iterative Shrinkage-Thresholding Algorithm (FISTA) is an accelerated proximal gradient method that achieves O(1/k^2) convergence rate for convex optimization problems. It can handle L1 regularization (sparsity), TV regularization, and box constraints.

Based on IRtools IRfista.m by Silvia Gazzola et al.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial guess for spectrum. If None, a flat spectrum is used.

  • max_iterations (int, optional) – Maximum number of iterations (default: 500).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-8).

  • regularization (float, optional) – Tikhonov regularization parameter (default: 0.0).

  • l1_penalty (float, optional) – L1 regularization penalty parameter for sparsity (default: 0.0).

  • tv_penalty (float, optional) – Total variation penalty parameter (default: 0.0).

  • nonnegativity (bool, optional) – Apply nonnegativity constraints (default: True).

  • x_min (float, optional) – Lower bound for solution (default: 0.0).

  • x_max (float, optional) – Upper bound for solution (default: inf).

  • noise_level (float, optional) – Relative noise level for discrepancy principle stopping.

  • eta (float, optional) – Safety factor for discrepancy principle (default: 1.01).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_ensemble(readings: dict[str, float], initial_spectrum: ndarray | None = None, methods: list[tuple[Callable, dict[str, Any]]] | None = None, weights: ndarray | None = None, combination: str = 'weighted_average', trim_fraction: float = 0.2, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using ensemble method.

Combines results from multiple base unfolding methods for robust reconstruction. Different methods have different biases; the ensemble reduces variance and is more robust to method-specific failures.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • methods (list of (callable, dict), optional) – Solver functions and their keyword arguments.

  • weights (np.ndarray, optional) – Per-method weights for weighted average.

  • combination (str, optional) – Combination strategy: ‘weighted_average’, ‘median’, ‘trimmed_mean’, or ‘best_residual’ (default: ‘weighted_average’).

  • trim_fraction (float, optional) – Trim fraction for trimmed mean (default: 0.2).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_iterative_refinement(readings: dict[str, float], initial_spectrum: ndarray | None = None, first_pass_kwargs: dict[str, Any] | None = None, second_pass_kwargs: dict[str, Any] | None = None, alpha: float | None = None, max_alpha_search: int = 20, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using iterative refinement.

Two-pass method: first pass (MLEM) captures gross structure, second pass (Landweber) corrects systematic errors via residual.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • first_pass_kwargs (dict, optional) – Keyword arguments for first-pass solver.

  • second_pass_kwargs (dict, optional) – Keyword arguments for second-pass solver.

  • alpha (float, optional) – Blending factor (None = auto-select via line search).

  • max_alpha_search (int, optional) – Number of alpha candidates for line search (default: 20).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_hybrid_gmres(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 100, regularization_method: str = 'gcv', regularization: float = 0.0, noise_level: float | None = None, eta: float = 1.01, reorthogonalization: bool = True, calculate_errors: bool = False, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Hybrid GMRES method.

The hybrid GMRES method combines the GMRES iterative solver with Tikhonov regularization applied to the projected problem at each iteration. The regularization parameter is selected automatically using GCV or discrepancy principle.

Based on IRtools IRhybrid_gmres.m by Silvia Gazzola et al.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial guess for spectrum. If None, zero vector is used.

  • max_iterations (int, optional) – Maximum Krylov dimension (default: 100).

  • regularization_method (str, optional) – Method for selecting regularization parameter: ‘gcv’, ‘modgcv’, ‘discrep’ (default: ‘gcv’).

  • regularization (float, optional) – Fixed regularization parameter (used if not auto-selected).

  • noise_level (float, optional) – Relative noise level for discrepancy principle.

  • eta (float, optional) – Safety factor for discrepancy principle (default: 1.01).

  • reorthogonalization (bool, optional) – Apply full reorthogonalization (default: True).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_fruit_like(readings: dict[str, float], initial_spectrum: ndarray | None = None, initial_params: dict[str, float] | None = None, method: str = 'leastsq', calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using FRUIT-like parametric method.

Uses a parametric model with Maxwellian thermal component, 1/E epithermal component, and evaporation spectrum for fast neutrons.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (unused in parametric method).

  • initial_params (Optional[Dict[str, float]], optional) – Initial parameter values for the parametric model. Keys: A_th, T_th, A_epi, A_f, T_ev.

  • method (str, optional) – lmfit solver method (default: “leastsq”).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_fission_ga(readings: dict[str, float], initial_spectrum: ndarray | None = None, initial_params: dict[str, float] | None = None, fit_scale: bool = True, ga_popsize: int = 15, ga_maxiter: int = 100, ga_tol: float = 1e-10, lm_method: str = 'trf', lm_max_nfev: int = 2000, eps_threshold: float = 0.05, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using the Fission-model GA+LM algorithm (BonnerFinder).

Python port of the multisphere unfolding algorithm of Ogorodnikov (2024), sections 4-5 (BonnerFinder()), which follows the FRUIT paradigm of parameterized model curves. The spectrum is modelled by the three-fraction Fission model (thermal Maxwellian, epithermal tail with cutoff, Watt-type fast fission peak) with seven free parameters. Stage 1 searches the parameter hypercube globally with a genetic (differential evolution) algorithm minimizing the L1 discrepancy of the folded readings; stage 2 refines the best point with a nonlinear least-squares routine. The article’s validation criteria (per-sphere relative uncertainties, sign alternation, FOM, spectrum norm) are attached to the result.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (unused by the parametric method).

  • initial_params (Optional[Dict[str, float]], optional) – Optional starting parameter values (a1, a2, a3, b, beta, alpha, TF, optionally phi_scale); refined as an extra stage-2 start.

  • fit_scale (bool, optional) – Fit a free overall scale factor so the model matches absolutely calibrated readings (default: True). Set False for the exact 7-parameter normalized formulation of the article (adds the norm-in-[0.6, 1.2] validation check).

  • ga_popsize (int, optional) – Population multiplier of the genetic algorithm (default: 15).

  • ga_maxiter (int, optional) – Maximum number of GA generations (default: 100).

  • ga_tol (float, optional) – GA convergence tolerance (default: 1e-10).

  • lm_method (str, optional) – Stage-2 least-squares method: "trf" (bounded, default) or "lm" (Levenberg-Marquardt, as in the article).

  • lm_max_nfev (int, optional) – Maximum function evaluations of one stage-2 run (default: 2000).

  • eps_threshold (float, optional) – Threshold on per-sphere relative uncertainty used by the validation criteria (default: 0.05).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • max_neutron_energy (float, optional) – Truncate the energy grid above this value (MeV).

Returns:

Unfolding results dictionary with additional keys model_params (fitted Fission-model parameters including weight_fractions) and validation (article’s validation criteria).

Return type:

Dict[str, Any]

unfold_hybrid_parametric(readings: dict[str, float], initial_spectrum: ndarray | None = None, refinement_method: str = 'landweber', max_iterations: int = 100, tolerance: float = 1e-06, step_size: float = 0.01, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using hybrid parametric-nonparametric method.

Combines parametric initial guess with iterative refinement using Landweber or MLEM iteration.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • refinement_method (str, optional) – Refinement method: “landweber” or “mlem” (default: “landweber”).

  • max_iterations (int, optional) – Maximum iterations (default: 100).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

  • step_size (float, optional) – Step size for Landweber (default: 0.01).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_bayesian_parametric(readings: dict[str, float], initial_spectrum: ndarray | None = None, sigma: float = 0.02, n_samples: int = 1000, burn_in: int = 200, proposal_scale: float = 0.1, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Bayesian parametric method.

Uses Bayesian inference with MCMC sampling to estimate spectral parameters and quantify uncertainty.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (unused).

  • sigma (float, optional) – Measurement uncertainty (default: 0.02).

  • n_samples (int, optional) – Number of MCMC samples (default: 1000).

  • burn_in (int, optional) – Burn-in samples (default: 200).

  • proposal_scale (float, optional) – Proposal scale (default: 0.1).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_parametric(readings: dict[str, float], initial_spectrum: ndarray | None = None, initial_params: dict[str, float] | None = None, method: str = 'leastsq', optimizer: str = 'lmfit', alpha: float = 0.0001, alpha_auto: bool = False, solver_backend: str = 'auto', max_iter: int = 50, tol: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the FRUIT-based parametric method.

Uses the three-component parameterization from Bedogni FRUIT / Pyshkina B3S: thermal (Maxwellian), epithermal (1/E with exponential cutoffs), and fast (power-law x exponential).

The optimizer parameter selects the backend:

  • "lmfit" – classic lmfit least-squares (default).

  • "cvxpy" – sequential QP via cvxpy (SQP).

  • "qpsolvers" – sequential QP via qpsolvers (SQP).

  • "combined" – lmfit first, then QP refinement.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (unused in parametric method).

  • initial_params (Optional[Dict[str, float]], optional) – Initial parameter values for the parametric model. Keys: b, beta_prime, alpha, beta, P_th, P_epi.

  • method (str, optional) – lmfit solver method (default: “leastsq”).

  • optimizer (str, optional) – Backend optimizer (default: “lmfit”).

  • alpha (float, optional) – Regularization weight for QP-based optimizers (default: 1e-4).

  • alpha_auto (bool, optional) – If True, select alpha automatically via GCV for the lmfit optimizer (default: False).

  • solver_backend (str, optional) – QP solver backend: “auto”, “cvxpy”, “cvxpy:ECOS”, “qpsolvers”, “qpsolvers:osqp”, etc. (default: “auto”).

  • max_iter (int, optional) – Max SQP iterations (default: 50).

  • tol (float, optional) – Convergence tolerance for SQP (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_parametric2(readings: dict[str, float], initial_spectrum: ndarray | None = None, optimizer: str = 'grid', b_range: tuple[float, float, int] = (0.5, 2.0, 5), Tf_range: tuple[float, float, int] = (0.5, 10.0, 5), c_range: tuple[float, float, int] = (0.5, 3.0, 4), alpha: float = 0.0001, solver_backend: str = 'auto', max_iter_qp: int = 50, tol_qp: float = 1e-06, noise_level: float = 0.05, max_iter: int = 200, tol_chi2: float = 1.0, calculate_errors: bool = False, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the BON95 parametric method.

Uses the four-component parameterization from Sannikov BON95: thermal (Maxwellian), epithermal (1/E), intermediate, and fast (evaporation/cascade) components. After parametric fitting, the result is refined by directed-divergence iterations.

The optimizer parameter selects the parametric fit backend:

  • "grid" – grid search + NLS (default, no extra deps).

  • "cvxpy" – SQP via cvxpy.

  • "qpsolvers" – SQP via qpsolvers.

  • "combined" – grid search + SQP refinement.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (unused in parametric method).

  • optimizer (str) – Parametric fit optimizer (default: “grid”).

  • b_range (tuple) – Grid range for b: (min, max, n_points). Used by “grid”/”combined”.

  • Tf_range (tuple) – Grid range for Tf (MeV): (min, max, n_points). Used by “grid”/”combined”.

  • c_range (tuple) – Grid range for c: (min, max, n_points). Used by “grid”/”combined”.

  • alpha (float) – Tikhonov regularization for SQP (default: 1e-4).

  • solver_backend (str) – QP backend for SQP (default: “auto”).

  • max_iter_qp (int) – Max SQP iterations (default: 50).

  • tol_qp (float) – SQP convergence tolerance (default: 1e-6).

  • noise_level (float) – Relative uncertainty for measurements (default: 0.05 = 5%).

  • max_iter (int) – Max directed-divergence iterations (default: 200).

  • tol_chi2 (float) – Chi-squared convergence threshold (default: 1.0).

  • calculate_errors (bool) – Calculate Monte-Carlo errors (default: False).

  • n_montecarlo (int) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • max_neutron_energy (float, optional) – Upper energy cutoff in MeV. Bins above this energy are excluded from the unfolding and set to zero in the returned spectrum.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_eki(readings: dict[str, float], initial_spectrum: ndarray | None = None, n_ensemble: int = 50, n_iterations: int = 50, regularization: float = 0.0001, inflation: float = 1.02, noise_std: float | None = None, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Ensemble Kalman Inversion (EKI).

Approximates the Bayesian posterior without MCMC by propagating an ensemble of particles through the forward model and updating via the Kalman gain equation (Iglesias et al., 2013).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (centre of the ensemble).

  • n_ensemble (int, optional) – Number of ensemble members (default: 50).

  • n_iterations (int, optional) – Number of EKI iterations (default: 50).

  • regularization (float, optional) – Regularization for covariance stability (default: 1e-4).

  • inflation (float, optional) – Covariance inflation factor (default: 1.02).

  • noise_std (float, optional) – Measurement noise std (default: None = auto).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • max_neutron_energy (float, optional) – Maximum neutron energy cutoff.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

plot_response_functions(save_to: str | None = None, show: bool = True, dpi: int = 300, bbox_inches: str = 'tight', **savefig_kwargs) None[source]#

Plot all detector response functions.

plot_with_uncertainty(result: dict[str, Any], reference_spectrum: dict[str, ndarray] | None = None, save_to: str | None = None, show: bool = True, **plot_kwargs) tuple[Any, Any][source]#

Plot unfolded spectrum with uncertainty range.

Parameters:
  • result (Dict[str, Any]) – Unfolding result dictionary containing ‘energy’, ‘spectrum’, and optionally ‘spectrum_uncert_min’, ‘spectrum_uncert_max’, ‘spectrum_uncert_std’.

  • reference_spectrum (Dict[str, np.ndarray], optional) – Reference spectrum with ‘E_MeV’ and ‘Phi’ keys.

  • save_to (str, optional) – Path to save figure.

  • show (bool, optional) – Call plt.show() (default: True).

  • **plot_kwargs (dict) – Additional keyword arguments for plotting.

Returns:

Figure and axes objects.

Return type:

Tuple[plt.Figure, plt.Axes]

compare_regularization_methods(readings: dict[str, float], noise_var: float | None = None, plot: bool = False, plot_path: str | None = None) dict[str, Any][source]#

Compare regularization selection methods for given readings.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • noise_var (float, optional) – Noise variance for discrepancy principle.

  • plot (bool, optional) – If True, generate comparison plot.

  • plot_path (str, optional) – Path to save the plot.

Returns:

Comparison results.

Return type:

Dict[str, Any]

randomization_experiment(readings: dict[str, float], noise_var: float | None = None, n_samples: int = 10, rseed: int = 0, methods: list[str] | None = None) dict[str, Any][source]#

Run randomization experiments for given readings.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • noise_var (float, optional) – Noise variance for generating perturbed measurements.

  • n_samples (int, optional) – Number of random samples for each method, default 10.

  • rseed (int, optional) – Random seed for reproducibility, default 0.

  • methods (list of str, optional) – List of methods to run: ‘lcurve’, ‘dp’, ‘gcv’, ‘lcurve_full’.

Returns:

Randomization experiment results.

Return type:

Dict[str, Any]

compare(*spectra: Any, metrics: str | list[str] | None = None, labels: list[str] | None = None, readings1: ndarray | None = None, readings2: ndarray | None = None, response_matrix: ndarray | None = None, plot: bool = False, save_to: str | None = None, dpi: int = 300, figsize: tuple[int, int] = (14, 5), return_fig: bool = False, **plot_kwargs) dict[str, float] | DataFrame | tuple[dict[str, float] | DataFrame, Any, Any][source]#

Compare two or more spectra using comparison metrics.

Each spectrum can be provided as: - np.ndarray of length matching self.n_energy_bins - dict with a 'spectrum' key (e.g. an unfolding result) - result dictionary returned by any unfold_* method

When the energy grid is available, EURADOS-style metrics (dose differences, peak errors, log-lethargy correlation, etc.) are computed automatically.

Parameters:
  • *spectra (np.ndarray or dict) – Two or more spectra to compare.

  • metrics (str, list of str, or None) – Metric(s) to compute. If None, all metrics are used.

  • labels (list of str, optional) – Labels for each spectrum. Required for 3+ spectra.

  • readings1 (np.ndarray, optional) – Measured readings for response-matrix consistency check. If a spectrum is a result dict containing 'readings', those values are used as a fallback.

  • readings2 (np.ndarray, optional) – Measured readings for response-matrix consistency check. If a spectrum is a result dict containing 'readings', those values are used as a fallback.

  • response_matrix (np.ndarray, optional) – Response matrix for the consistency check. If a spectrum is a result dict containing 'response_matrix', that value is used as a fallback.

  • plot (bool, optional) – If True, generate a comparison figure with spectra overlay and metric bar chart.

  • save_to (str, optional) – Path to save the figure (png/jpg/eps/pdf).

  • dpi (int, optional) – Figure DPI (default: 300).

  • figsize (tuple, optional) – Figure size (default: (14, 5)).

  • return_fig (bool, optional) – If True, return (result, fig, ax) tuple.

  • **plot_kwargs (dict) – Additional keyword arguments passed to matplotlib/seaborn plots.

Returns:

If two spectra: dict {metric: value}. If three or more: pd.DataFrame with metrics as rows and comparison pairs as columns. If return_fig=True: (result, fig, ax).

Return type:

dict or pd.DataFrame or tuple

unfold_pgd(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 1000, tolerance: float = 1e-06, regularization: float = 0.0, constraint: str = 'nonnegative', total_fluence: float | None = None, x_max: float = inf, backtracking: bool = False, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, variance_reduction: str = 'none', save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using projected gradient descent.

Solves min 1/2||Ax-b||^2 + reg/2||x||^2 with the iterates projected onto the constraint set at every step (‘nonnegative’, ‘box’ or ‘simplex’); the simplex option keeps the total fluence exactly fixed. A duality-gap certificate (Lagrange duality / KKT diagnostics) is appended to the result as duality_gap.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum iterations (default: 1000).

  • tolerance (float, optional) – Relative change tolerance (default: 1e-6).

  • regularization (float, optional) – Tikhonov regularization strength (default: 0.0).

  • constraint (str, optional) – 'nonnegative', 'box' or 'simplex' (default: ‘nonnegative’).

  • total_fluence (Optional[float], optional) – Total fluence for the simplex constraint.

  • x_max (float, optional) – Upper bound for the box constraint (default: inf).

  • backtracking (bool, optional) – Use Armijo backtracking (default: False).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • variance_reduction (str, optional) – MC variance reduction: ‘none’, ‘antithetic’, ‘control’, ‘both’.

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • max_neutron_energy (Optional[float], optional) – Restrict the energy grid to bins below this energy.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_mirror_descent(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 2000, tolerance: float = 1e-08, mirror_map: str = 'entropy', step_size: float | None = None, total_fluence: float | None = None, regularization: float = 0.0, p: float = 3.0, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, variance_reduction: str = 'none', save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using mirror descent.

Bregman-geometry descent: the ‘entropy’ mirror map yields multiplicative updates generalizing MLEM/GRAVEL/SAND-II and keeps the total fluence constant; ‘log’, ‘l2’ and ‘pnorm’ maps give other non-negative geometries.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (strictly positive for ‘entropy’/’log’).

  • max_iterations (int, optional) – Maximum iterations (default: 2000).

  • tolerance (float, optional) – Relative change tolerance (default: 1e-8).

  • mirror_map (str, optional) – 'entropy', 'log', 'l2' or 'pnorm' (default: ‘entropy’).

  • step_size (Optional[float], optional) – Mirror step; golden-section line search when None.

  • total_fluence (Optional[float], optional) – Simplex level for the entropy map.

  • regularization (float, optional) – Tikhonov regularization strength (default: 0.0).

  • p (float, optional) – Order of the p-norm mirror map (default: 3.0).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • variance_reduction (str, optional) – MC variance reduction: ‘none’, ‘antithetic’, ‘control’, ‘both’.

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • max_neutron_energy (Optional[float], optional) – Restrict the energy grid to bins below this energy.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_frank_wolfe(readings: dict[str, float], initial_spectrum: ndarray | None = None, total_fluence: float | None = None, max_iterations: int = 1000, tolerance: float = 1e-08, away_steps: bool = True, line_search: str = 'exact', calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, variance_reduction: str = 'none', save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the Frank-Wolfe algorithm.

Conditional-gradient method on the fluence simplex: each iteration solves a linear minimization oracle (single active bin) and moves a fraction towards it; the total fluence is preserved exactly. Optional Wolfe away-steps reduce zig-zagging near the optimum.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (projected onto the simplex).

  • total_fluence (Optional[float], optional) – Simplex level F; estimated from a uniform fit when None.

  • max_iterations (int, optional) – Maximum iterations (default: 1000).

  • tolerance (float, optional) – Frank-Wolfe gap tolerance (default: 1e-8).

  • away_steps (bool, optional) – Use Wolfe away-steps (default: True).

  • line_search (str, optional) – 'exact' or 'backtracking' (default: ‘exact’).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • variance_reduction (str, optional) – MC variance reduction: ‘none’, ‘antithetic’, ‘control’, ‘both’.

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • max_neutron_energy (Optional[float], optional) – Restrict the energy grid to bins below this energy.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_admm(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 500, tolerance: float = 1e-06, l1_penalty: float = 0.0, tv_penalty: float = 0.0, rho: float | None = None, adaptive_rho: bool = True, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, variance_reduction: str = 'none', save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using consensus ADMM.

Splits the L1/TV-regularized NNLS problem into an exact NNLS x-update (non-negativity enforced at every iteration), soft- thresholding z-updates and dual ascent; rho is adapted automatically (Boyd et al., sec. 3.4.1).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum outer iterations (default: 500).

  • tolerance (float, optional) – Relative change tolerance (default: 1e-6).

  • l1_penalty (float, optional) – L1 (sparsity) penalty weight (default: 0.0).

  • tv_penalty (float, optional) – Total-variation penalty weight (default: 0.0).

  • rho (Optional[float], optional) – ADMM penalty parameter (auto when None).

  • adaptive_rho (bool, optional) – Adapt rho every 10 iterations (default: True).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • variance_reduction (str, optional) – MC variance reduction: ‘none’, ‘antithetic’, ‘control’, ‘both’.

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • max_neutron_energy (Optional[float], optional) – Restrict the energy grid to bins below this energy.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_lbfgsb(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 500, tolerance: float = 1e-08, regularization: float = 0.0, smoothness: float = 0.0, x_min: float = 0.0, x_max: float = inf, lbfgs_history: int = 10, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, variance_reduction: str = 'none', save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the L-BFGS-B quasi-Newton method.

Limited-memory BFGS with box bounds minimizes the smooth Tikhonov objective with analytic gradients; smoothness adds a second-difference (curvature) penalty against oscillations.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum iterations (default: 500).

  • tolerance (float, optional) – Gradient-norm stopping tolerance (default: 1e-8).

  • regularization (float, optional) – Tikhonov (L2) regularization strength (default: 0.0).

  • smoothness (float, optional) – Second-difference penalty weight (default: 0.0).

  • x_min (float, optional) – Lower bound (default: 0.0).

  • x_max (float, optional) – Upper bound (default: inf).

  • lbfgs_history (int, optional) – L-BFGS memory (default: 10).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • variance_reduction (str, optional) – MC variance reduction: ‘none’, ‘antithetic’, ‘control’, ‘both’.

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • max_neutron_energy (Optional[float], optional) – Restrict the energy grid to bins below this energy.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_coordinate_descent(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 2000, tolerance: float = 1e-08, l1_penalty: float = 0.0, l2_penalty: float = 0.0, selection: str = 'cyclic', calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, variance_reduction: str = 'none', save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using coordinate descent.

Exact closed-form coordinate minimization of the NNLS objective with optional L1/L2 penalties; O(m) per coordinate via a running residual, cyclic or random coordinate order.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum sweeps (default: 2000).

  • tolerance (float, optional) – Relative change tolerance (default: 1e-8).

  • l1_penalty (float, optional) – L1 penalty weight (default: 0.0).

  • l2_penalty (float, optional) – Ridge penalty weight (default: 0.0).

  • selection (str, optional) – 'cyclic' or 'random' (default: ‘cyclic’).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • variance_reduction (str, optional) – MC variance reduction: ‘none’, ‘antithetic’, ‘control’, ‘both’.

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed (also used by ‘random’ selection).

  • max_neutron_energy (Optional[float], optional) – Restrict the energy grid to bins below this energy.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_subgradient(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 3000, tolerance: float = 1e-08, l1_penalty: float = 0.0, tv_penalty: float = 0.0, step_policy: str = 'diminishing', step_size: float = 1.0, decay: float = 1.0, polyak_margin: float = 0.05, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, variance_reduction: str = 'none', save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using projected subgradient descent.

Nonsmooth L1/TV penalties handled natively via subgradients with Polyak / diminishing / fixed step-size policies; the best iterate by objective value is returned.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum iterations (default: 3000).

  • tolerance (float, optional) – Relative change tolerance (default: 1e-8).

  • l1_penalty (float, optional) – L1 penalty weight (default: 0.0).

  • tv_penalty (float, optional) – TV penalty weight (default: 0.0).

  • step_policy (str, optional) – 'polyak', 'diminishing' or 'fixed' (default: ‘diminishing’).

  • step_size (float, optional) – Base step size (default: 1.0).

  • decay (float, optional) – Diminishing-step decay rate (default: 1.0).

  • polyak_margin (float, optional) – Relative margin for the Polyak optimal-value estimate (default: 0.05).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • variance_reduction (str, optional) – MC variance reduction: ‘none’, ‘antithetic’, ‘control’, ‘both’.

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • max_neutron_energy (Optional[float], optional) – Restrict the energy grid to bins below this energy.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_extragradient(readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 2000, tolerance: float = 1e-08, noise_level: float = 0.02, step_size: float | None = None, calculate_errors: bool = False, mc_noise_level: float = 0.01, n_montecarlo: int = 100, variance_reduction: str = 'none', save_result: bool = False, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Korpelevich’s extragradient.

Solves the robust saddle formulation min_{x>=0} 1/2||Ax-b||^2 + delta*||Ax-b||_2 (guarding against measurement noise of L2 norm up to delta = noise_level * ||b||_2) via its bilinear saddle form with the two-step extragradient scheme.

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum iterations (default: 2000).

  • tolerance (float, optional) – Relative change tolerance (default: 1e-8).

  • noise_level (float, optional) – Relative noise-ball radius (default: 0.02).

  • step_size (Optional[float], optional) – Extragradient step; auto from the Lipschitz bound when None.

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • mc_noise_level (float, optional) – Noise level for Monte-Carlo uncertainty (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • variance_reduction (str, optional) – MC variance reduction: ‘none’, ‘antithetic’, ‘control’, ‘both’.

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • max_neutron_energy (Optional[float], optional) – Restrict the energy grid to bins below this energy.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

unfold_cuqi(readings: dict[str, float], initial_spectrum: ndarray | None = None, sampler: str = 'pcn', noise_level: float = 0.05, prior: str = 'gmrf', gmrf_order: int = 1, lengthscale: float = 3.0, prec: float = 1.0, hierarchical: bool | None = None, delta_alpha: float = 1.0, delta_beta: float = 0.0001, n_samples: int = 2000, n_burnin: int = 1000, thin: int = 1, chains: int = 2, scale: float = 0.05, max_depth: int = 8, step_size: float | None = None, credible_level: float = 95.0, calculate_errors: bool = False, mc_noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, progressbar: bool = False, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum with CUQIpy Bayesian samplers.

Full Bayesian unfolding powered by CUQIpy (Computational Uncertainty Quantification for Inverse Problems, DTU). The spectrum is modelled on the log scale with a smoothness prior (GMRF or Ornstein-Uhlenbeck Gaussian) anchored on a data-driven center, and the posterior is explored with one of the CUQIpy samplers:

  • 'pcn' : Preconditioned Crank-Nicolson

  • 'cwmh' : Component-wise Metropolis-Hastings

  • 'ula' : Unadjusted Langevin algorithm

  • 'mala' : Metropolis-adjusted Langevin algorithm

  • 'nuts' : No-U-Turn Sampler

  • 'gibbs' / 'gibbs_nuts' : hierarchical Gibbs sampling where the GMRF smoothness precision is inferred from the data through a conjugate Gamma hyperprior (CUQIpy HybridGibbs)

The result contains the mean posterior spectrum, per-bin posterior standard deviations, 95% (configurable) HPD credible intervals and convergence diagnostics (ESS, R-hat, acceptance rate) under result['cuqi_stats'].

Requires the optional cuqipy package (pip install bssunfold[cuqi] or pip install cuqipy).

Parameters:
  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Prior center guess for the spectrum. When None, the non-negative least-squares solution of A @ x = b is used as the prior center.

  • sampler (str, optional) – CUQIpy sampler (default: 'pcn').

  • noise_level (float, optional) – Relative likelihood noise scale (default: 0.05).

  • prior (str, optional) – Log-spectrum prior: 'gmrf' (default) or 'ou'.

  • gmrf_order (int, optional) – GMRF operator order, 1 or 2 (default: 1); higher is smoother.

  • lengthscale (float, optional) – OU correlation length in energy bins (default: 3.0).

  • prec (float, optional) – Fixed prior precision scale (default: 1.0); inferred from the data by the hierarchical Gibbs samplers.

  • hierarchical (bool, optional) – Force the hierarchical Gibbs scheme (default: derived from sampler).

  • delta_alpha (float, optional) – Gamma hyperprior shape for the GMRF precision (default: 1.0).

  • delta_beta (float, optional) – Gamma hyperprior rate for the GMRF precision (default: 1e-4).

  • n_samples (int, optional) – Posterior samples per chain (default: 2000).

  • n_burnin (int, optional) – Warmup iterations per chain (default: 1000).

  • thin (int, optional) – Thinning interval (default: 1).

  • chains (int, optional) – Number of independent chains (default: 2).

  • scale (float, optional) – Proposal step size (default: 0.05).

  • max_depth (int, optional) – NUTS maximum tree depth (default: 8).

  • step_size (float, optional) – NUTS leapfrog step size (default: None, tuned by CUQIpy).

  • credible_level (float, optional) – Credible mass (%) of the HPD interval (default: 95).

  • calculate_errors (bool, optional) – Calculate additional Monte-Carlo errors (default: False).

  • mc_noise_level (float, optional) – Noise level for the additional Monte-Carlo loop (default: 0.01).

  • n_montecarlo (int, optional) – Number of additional Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • progressbar (bool, optional) – Present for API consistency (default: False).

  • max_neutron_energy (Optional[float], optional) – Truncate the response matrices above this energy (MeV).

Returns:

Unfolding results dictionary. Includes the standard keys (energy, spectrum, effective_readings, residual, residual_norm, method, doserates) plus CUQI-specific keys spectrum_uncertainty, spectrum_lower, spectrum_upper and cuqi_stats.

Return type:

Dict[str, Any]

Raises:
  • ImportError – If CUQIpy is not installed.

  • RuntimeError – If MCMC sampling fails.

Examples

>>> from bssunfold import Detector
>>> detector = Detector()
>>> result = detector.unfold_cuqi(
...     readings,
...     sampler='gibbs_nuts',
...     n_samples=1000,
...     chains=2,
... )
>>> spectrum = result['spectrum']
>>> acc = result['cuqi_stats']['acc_rate']

See also

unfold_mcmc

PyMC/NUTS Bayesian unfolding

unfold_bayes

Bayesian iterative unfolding (D’Agostini)

Unfold Methods#

The following unfolding methods are available through the Detector class:

bssunfold.core.unfold_cvxpy.unfold_cvxpy(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0001, norm: int = 2, solver: str = 'default', calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, regularization_method: str = 'manual', noise_var: float | None = None, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold neutron spectrum using convex optimization (cvxpy).

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • regularization (float, optional) – Regularization parameter (default: 1e-4).

  • norm (int, optional) – Norm type (1 for L1, 2 for L2), default: 2.

  • solver (str, optional) – Solver to use (‘ECOS’ or ‘default’).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • regularization_method (str, optional) – Method for selecting regularization parameter.

  • noise_var (float, optional) – Noise variance for discrepancy principle.

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_landweber.unfold_landweber(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 1000, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold using Landweber iteration method.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum iterations (default: 1000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_mlem.unfold_mlem(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 1000, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold using MLEM algorithm.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum iterations (default: 1000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_qpsolvers.unfold_qpsolvers(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0001, norm: int = 2, solver: str = 'osqp', calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, regularization_method: str = 'manual', noise_var: float | None = None, smoothness_order: int = 0, smoothness_weight: float = 1.0, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using qpsolvers with regularization selection.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess.

  • regularization (float, optional) – Regularization parameter, default: 1e-4.

  • norm (int, optional) – Norm type (1 for L1, 2 for L2), default: 2.

  • solver (str, optional) – QP solver name, default: ‘osqp’.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default: False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default: 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default: 100.

  • save_result (bool, optional) – Save result to history, default: False.

  • regularization_method (str, optional) – Method for selecting regularization parameter.

  • noise_var (float, optional) – Noise variance for discrepancy principle (‘dp’ method).

  • smoothness_order (int, optional) – Smoothness constraint order (0, 1, or 2), default: 0.

  • smoothness_weight (float, optional) – Weight for smoothness term, default: 1.0.

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

Dict[str, Any]

bssunfold.core.unfold_mystic.unfold_mystic(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0001, norm: int = 2, solver: str = 'fmin_powell', maxiter: int | None = 2000, maxfun: int | None = 20000, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, regularization_method: str = 'manual', noise_var: float | None = None, smoothness_order: int = 0, smoothness_weight: float = 1.0, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold using mystic with regularization selection.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess.

  • regularization (float, optional) – Regularization parameter, default: 1e-4.

  • norm (int, optional) – Norm type (1 for L1, 2 for L2), default: 2.

  • solver (str, optional) – Mystic solver name, default: ‘fmin_powell’.

  • maxiter (int, optional) – Maximum number of solver iterations, default: 2000.

  • maxfun (int, optional) – Maximum number of function evaluations, default: 20000.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default: False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default: 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default: 100.

  • save_result (bool, optional) – Save result to history, default: False.

  • regularization_method (str, optional) – Method for selecting regularization parameter.

  • noise_var (float, optional) – Noise variance for discrepancy principle (‘dp’ method).

  • smoothness_order (int, optional) – Smoothness constraint order (0, 1, or 2), default: 0.

  • smoothness_weight (float, optional) – Weight for smoothness term, default: 1.0.

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

Dict[str, Any]

bssunfold.core.unfold_mystic.unfold_mystic_hybrid(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0001, norm: int = 2, global_solver: str = 'diffev2', local_solver: str = 'fmin_powell', global_maxiter: int | None = None, global_maxfun: int | None = None, local_maxiter: int | None = None, local_maxfun: int | None = None, npop: int | None = None, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, regularization_method: str = 'manual', noise_var: float | None = None, smoothness_order: int = 0, smoothness_weight: float = 1.0, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Two-stage hybrid unfolding: global search + local refinement.

Stage 1 uses a population-based solver (diffev2 by default) with automatically derived bounds to robustly locate the basin of the global minimum. Stage 2 feeds that result as x0 into a local direct-search solver (fmin_powell by default) for precise final convergence. This combines the robustness of global optimization with the accuracy of local optimization.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess for the global stage.

  • regularization (float, optional) – Regularization parameter, default: 1e-4.

  • norm (int, optional) – Norm type (1 for L1, 2 for L2), default: 2.

  • global_solver (str, optional) – Population-based solver for stage 1 ('diffev' or 'diffev2'), default: 'diffev2'.

  • local_solver (str, optional) – Local solver for stage 2 ('fmin' or 'fmin_powell'), default: 'fmin_powell'.

  • global_maxiter (int, optional) – Maximum iterations for the global stage (default: 200).

  • global_maxfun (int, optional) – Maximum function evaluations for the global stage.

  • local_maxiter (int, optional) – Maximum iterations for the local stage (default: 2000).

  • local_maxfun (int, optional) – Maximum function evaluations for the local stage.

  • npop (int, optional) – Population size for the global stage.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default: False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default: 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default: 100.

  • save_result (bool, optional) – Save result to history, default: False.

  • regularization_method (str, optional) – Method for selecting regularization parameter.

  • noise_var (float, optional) – Noise variance for discrepancy principle (‘dp’ method).

  • smoothness_order (int, optional) – Smoothness constraint order (0, 1, or 2), default: 0.

  • smoothness_weight (float, optional) – Weight for smoothness term, default: 1.0.

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

Dict[str, Any]

bssunfold.core.unfold_genetic.unfold_genetic(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, solver: str = 'pso', epoch: int = 500, pop_size: int = 50, regularization: float = 0.01, norm: int = 2, smoothness_order: int = 2, smoothness_weight: float = 1.0, entropy_weight: float = 0.0, n_runs: int = 1, early_stop: int | None = None, half_range: float = 2.0, two_step: bool = False, n_coarse: int | None = None, smoother: str = 'none', sigma_smooth: float = 2.0, crossover: str = 'single', mutation: str = 'random', pareto_select: str = 'knee', calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, verbose: bool = False) dict[str, Any][source]#

Unfold a neutron spectrum using a meta-heuristic algorithm.

The optimizer searches in log space seeded with a Landweber warm-start solution (or the provided initial_spectrum), bounded to log(seed) +/- half_range decades, with a scale-consistent objective.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess. If None, a Landweber warm-start solution is used to seed the population.

  • solver (str, optional) – Meta-heuristic algorithm: ‘pso’, ‘ga’, ‘de’, ‘es’, ‘ep’, ‘abc’, ‘gwo’, ‘cmaes’ or ‘nsga2’ (default: ‘pso’).

  • epoch (int, optional) – Maximum number of generations (default: 500).

  • pop_size (int, optional) – Population size (default: 50).

  • regularization (float, optional) – Tikhonov regularisation weight (default: 1e-2).

  • norm (int, optional) – Norm for the regularisation term (1 or 2), default: 2.

  • smoothness_order (int, optional) – Second-difference smoothing order (0, 1 or 2), default: 2.

  • smoothness_weight (float, optional) – Weight of the smoothing term (default: 1.0).

  • entropy_weight (float, optional) – Weight of the negative Shannon-entropy objective (default: 0).

  • n_runs (int, optional) – Number of independent runs to average (default: 1). Not used by the ‘nsga2’ solver.

  • early_stop (int, optional) – Early-stopping patience (epochs without improvement).

  • half_range (float, optional) – Half-width of the log-space search bounds in decades around the seed (default: 2.0).

  • two_step (bool, optional) – If True, run the two-step genetic scheme (TGASU-style) with a coarse first step seeding the full-resolution population (default: False).

  • n_coarse (int, optional) – Number of coarse bins for the two_step mode (default: None, i.e. max(8, n // 4)).

  • smoother (str, optional) – Post-processing smoother: ‘none’, ‘gaussian’, ‘mbc’, ‘gaussian_mbc’ or ‘second_difference’ (default: ‘none’).

  • sigma_smooth (float, optional) – Gaussian filter sigma for the smoothers (default: 2.0).

  • crossover (str, optional) – GA crossover operator: ‘single’ or ‘arithmetic’ (TGASU); only used by the numpy GA engine (default: ‘single’).

  • mutation (str, optional) – GA mutation operator: ‘random’ or ‘iterative’ (TGASU, decreasing step); only used by the numpy GA engine (default: ‘random’).

  • pareto_select (str, optional) – Selection from the Pareto front for the ‘nsga2’ solver: ‘knee’, ‘min_residual’ or ‘max_entropy’ (default: ‘knee’).

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default: False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default: 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default: 100.

  • save_result (bool, optional) – Save result to history, default: False.

  • random_state (int, optional) – Random seed for reproducibility.

  • verbose (bool, optional) – If True, print the MEALPY optimisation progress.

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

Dict[str, Any]

bssunfold.core.unfold_gnowee.unfold_gnowee(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, population: int = 25, max_gens: int = 200, max_fevals: int = 5000, stall_limit: int = 200, conv_tol: float = 1e-06, opt_conv_tol: float = 0.01, frac_elite: float = 0.2, frac_levy: float = 1.0, frac_mutation: float = 0.2, alpha_levy: float = 1.5, gamma_levy: float = 1.0, n_levy: int = 1, scaling_factor: float = 10.0, init_sampling: str = 'lhc', regularization: float = 0.01, norm: int = 2, smoothness_order: int = 2, smoothness_weight: float = 1.0, entropy_weight: float = 0.0, half_range: float = 2.0, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, verbose: bool = False) dict[str, Any][source]#

Unfold a neutron spectrum using the Gnowee metaheuristic optimizer.

The optimizer searches in log space seeded with a Landweber warm-start solution (or the provided initial_spectrum), bounded to log(seed) ± half_range decades, with a scale-consistent objective combining the relative L2 residual, Tikhonov regularisation, second-difference smoothness and (optionally) negative Shannon entropy.

Parameters:
  • detector_names (list[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess. If None, a Landweber warm-start solution is used to seed the population.

  • population (int, optional) – Population size, default 25.

  • max_gens (int, optional) – Maximum generations, default 200.

  • max_fevals (int, optional) – Maximum fitness evaluations, default 5_000.

  • stall_limit (int, optional) – Stall-based termination threshold (evaluations), default 200.

  • conv_tol (float, optional) – Relative improvement tolerance for timeline extension, default 1e-6.

  • opt_conv_tol (float, optional) – Tolerance on the optimum value for fitness convergence, default 1e-2.

  • frac_elite (float, optional) – Elite fraction for crossover/scatter-search, default 0.2.

  • frac_levy (float, optional) – Lévy flight fraction, default 1.0.

  • frac_mutation (float, optional) – Mutation discovery probability, default 0.2.

  • alpha_levy (float, optional) – Lévy exponent, default 1.5.

  • gamma_levy (float, optional) – Lévy scale, default 1.0.

  • n_levy (int, optional) – Independent Lévy samples, default 1.

  • scaling_factor (float, optional) – Lévy step scale, default 10.0.

  • init_sampling (str, optional) – Initial sampler: 'lhc' or 'random', default 'lhc'.

  • regularization (float, optional) – Tikhonov regularisation weight, default 1e-2.

  • norm (int, optional) – Norm for the regularisation term (1 or 2), default 2.

  • smoothness_order (int, optional) – Smoothness penalty order (0, 1 or 2), default 2.

  • smoothness_weight (float, optional) – Weight for the smoothness term, default 1.0.

  • entropy_weight (float, optional) – Weight of the negative Shannon-entropy objective (0 disables it).

  • half_range (float, optional) – Half-width of the log-space search bounds in decades, default 2.0.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default 100.

  • save_result (bool, optional) – Save result to history, default False.

  • random_state (int, optional) – Random seed for reproducibility.

  • verbose (bool, optional) – Print Gnowee progress.

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

dict[str, Any]

bssunfold.core.unfold_nnqp.unfold_nnqp(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0001, smoothness_order: int = 0, smoothness_weight: float = 1.0, tol: float = 1e-06, max_iterations: int = 10000, floor: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold a neutron spectrum using NNQP (non-negative QP by coordinate descent).

Solves

minimize 1/2 · ||A x − b||² + α/2 · ||L x||² + α0/2 · ||x||² subject to x ≥ 0

where L is the finite-difference derivative matrix of order smoothness_order, using the coordinate-descent NNQP solver of Giovannucci & Pehlevan (simonsfoundation/NNQP).

Parameters:
  • detector_names (list[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Warm-start spectrum. If None the NNQP solver uses a uniform random initial guess.

  • regularization (float, optional) – Tikhonov / smoothness regularisation weight (default 1e-4).

  • smoothness_order (int, optional) – Smoothness penalty order (0, 1 or 2), default 0.

  • smoothness_weight (float, optional) – Weight for the smoothness term (default 1.0).

  • tol (float, optional) – Convergence tolerance (default 1e-6).

  • max_iterations (int, optional) – Iteration cap (default 10 000).

  • floor (float, optional) – Diagonal regularisation floor added to Q to guarantee strict positive-definiteness (default 1e-6).

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default 100.

  • save_result (bool, optional) – Save result to history, default False.

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

dict[str, Any]

bssunfold.core.unfold_qpmad.unfold_qpmad(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0001, smoothness_order: int = 0, smoothness_weight: float = 1.0, floor: float = 1e-06, lb: ndarray | None = None, ub: ndarray | None = None, backend: str = 'python', tol: float = 1e-09, max_iterations: int = 10000, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold a neutron spectrum using qpmad (Goldfarb-Idnani dual active-set QP).

Solves

minimize 1/2 · ||A x − b||² + α/2 · ||L x||² + α0/2 · ||x||² subject to lb ≤ x ≤ ub (default: x ≥ 0)

by recasting it as the strictly-convex QP min 0.5 xᵀHx + gᵀx and applying the qpmad algorithm of Sherikov (asherikov/qpmad).

Parameters:
  • detector_names (list[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Accepted for API compatibility (the Goldfarb-Idnani algorithm starts from the unconstrained minimum, not from x0).

  • regularization (float, optional) – Tikhonov / smoothness regularisation weight (default 1e-4).

  • smoothness_order (int, optional) – Smoothness penalty order (0, 1 or 2), default 0.

  • smoothness_weight (float, optional) – Weight for the smoothness term (default 1.0).

  • floor (float, optional) – Diagonal regularisation floor added to H (default 1e-6).

  • lb (np.ndarray, optional) – Simple bounds on the spectrum. If both are None (default) the method enforces x 0.

  • ub (np.ndarray, optional) – Simple bounds on the spectrum. If both are None (default) the method enforces x 0.

  • backend (str, optional) – 'python' (default) uses a pure-NumPy port of Goldfarb-Idnani; 'qpmad' calls the upstream C++ library if its Python bindings are installed (falls back to 'python' otherwise).

  • tol (float, optional) – Numerical tolerance (default 1e-9).

  • max_iterations (int, optional) – Iteration cap for the Python backend (default 10 000).

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default 100.

  • save_result (bool, optional) – Save result to history, default False.

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

dict[str, Any]

bssunfold.core.unfold_pgd.unfold_pgd(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 1000, tolerance: float = 1e-06, regularization: float = 0.0, constraint: str = 'nonnegative', total_fluence: float | None = None, x_max: float = inf, backtracking: bool = False, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, variance_reduction: str = 'none', save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using projected gradient descent.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum iterations (default: 1000).

  • tolerance (float, optional) – Relative change tolerance (default: 1e-6).

  • regularization (float, optional) – Tikhonov regularization strength (default: 0.0).

  • constraint (str, optional) – Constraint set: 'nonnegative', 'box' or 'simplex' (default: ‘nonnegative’).

  • total_fluence (float, optional) – Total fluence for the simplex constraint (required for ‘simplex’).

  • x_max (float, optional) – Upper bound for the box constraint (default: inf).

  • backtracking (bool, optional) – Use Armijo backtracking (default: False).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • variance_reduction (str, optional) – Monte-Carlo variance reduction: 'none', 'antithetic', 'control' or 'both' (default: ‘none’).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_frank_wolfe.unfold_frank_wolfe(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, total_fluence: float | None = None, max_iterations: int = 1000, tolerance: float = 1e-08, away_steps: bool = True, line_search: str = 'exact', calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, variance_reduction: str = 'none', save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the Frank–Wolfe algorithm.

The spectrum is constrained to the simplex {x >= 0, sum(x) = F} where F defaults to the total fluence implied by an initial uniform fit.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (projected onto the simplex).

  • total_fluence (Optional[float], optional) – Simplex level F. If None, estimated from a uniform fit.

  • max_iterations (int, optional) – Maximum iterations (default: 1000).

  • tolerance (float, optional) – Frank-Wolfe gap tolerance (default: 1e-8).

  • away_steps (bool, optional) – Use Wolfe away-steps (default: True).

  • line_search (str, optional) – 'exact' or 'backtracking' (default: ‘exact’).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • variance_reduction (str, optional) – Monte-Carlo variance reduction: 'none', 'antithetic', 'control' or 'both' (default: ‘none’).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_mirror_descent.unfold_mirror_descent(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 2000, tolerance: float = 1e-08, mirror_map: str = 'entropy', step_size: float | None = None, total_fluence: float | None = None, regularization: float = 0.0, p: float = 3.0, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, variance_reduction: str = 'none', save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using mirror descent.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (strictly positive for ‘entropy’/’log’ maps).

  • max_iterations (int, optional) – Maximum iterations (default: 2000).

  • tolerance (float, optional) – Relative change tolerance (default: 1e-8).

  • mirror_map (str, optional) – 'entropy', 'log', 'l2' or 'pnorm' (default: ‘entropy’).

  • step_size (Optional[float], optional) – Mirror step size; default 1 / (||A||^2 + reg).

  • total_fluence (Optional[float], optional) – Total fluence for the entropy map (default: sum of initial spectrum, estimated from a uniform fit when not provided).

  • regularization (float, optional) – Tikhonov regularization strength (default: 0.0).

  • p (float, optional) – Order of the p-norm mirror map (default: 3.0).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • variance_reduction (str, optional) – Monte-Carlo variance reduction: 'none', 'antithetic', 'control' or 'both' (default: ‘none’).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_admm.unfold_admm(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 500, tolerance: float = 1e-06, l1_penalty: float = 0.0, tv_penalty: float = 0.0, rho: float | None = None, adaptive_rho: bool = True, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, variance_reduction: str = 'none', save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using consensus ADMM.

Supports exact L1 (sparsity) and 1D total-variation penalties together with the hard non-negativity constraint; the x-subproblem is solved exactly by NNLS, so the physical constraint holds at every iteration.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum outer iterations (default: 500).

  • tolerance (float, optional) – Relative change tolerance (default: 1e-6).

  • l1_penalty (float, optional) – L1 (sparsity) penalty weight (default: 0.0).

  • tv_penalty (float, optional) – Total-variation penalty weight ||D x||_1 (default: 0.0).

  • rho (Optional[float], optional) – ADMM penalty parameter; adapted automatically when None.

  • adaptive_rho (bool, optional) – Adapt rho every 10 iterations (default: True).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • variance_reduction (str, optional) – Monte-Carlo variance reduction: 'none', 'antithetic', 'control' or 'both' (default: ‘none’).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_lbfgsb.unfold_lbfgsb(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 500, tolerance: float = 1e-08, regularization: float = 0.0, smoothness: float = 0.0, x_min: float = 0.0, x_max: float = inf, lbfgs_history: int = 10, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, variance_reduction: str = 'none', save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the L-BFGS-B quasi-Newton method.

Minimizes the smooth Tikhonov objective with analytic gradients under box bounds x_min <= x <= x_max; smoothness adds a discrete Laplacian penalty against oscillations.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum iterations (default: 500).

  • tolerance (float, optional) – Gradient-norm stopping tolerance (default: 1e-8).

  • regularization (float, optional) – Tikhonov (L2) regularization strength (default: 0.0).

  • smoothness (float, optional) – Second-difference (curvature) penalty weight (default: 0.0).

  • x_min (float, optional) – Lower bound (default: 0.0).

  • x_max (float, optional) – Upper bound (default: inf).

  • lbfgs_history (int, optional) – L-BFGS memory (default: 10).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • variance_reduction (str, optional) – Monte-Carlo variance reduction: 'none', 'antithetic', 'control' or 'both' (default: ‘none’).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_coordinate_descent.unfold_coordinate_descent(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 2000, tolerance: float = 1e-08, l1_penalty: float = 0.0, l2_penalty: float = 0.0, selection: str = 'cyclic', calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, variance_reduction: str = 'none', save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using coordinate descent.

Exact closed-form coordinate minimization of the NNLS objective with optional L1/L2 penalties; O(m) per coordinate via a running residual.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum sweeps (default: 2000).

  • tolerance (float, optional) – Relative change tolerance (default: 1e-8).

  • l1_penalty (float, optional) – L1 penalty weight (default: 0.0).

  • l2_penalty (float, optional) – Ridge penalty weight (default: 0.0).

  • selection (str, optional) – 'cyclic' or 'random' coordinate order (default: ‘cyclic’).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • variance_reduction (str, optional) – Monte-Carlo variance reduction: 'none', 'antithetic', 'control' or 'both' (default: ‘none’).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility (also used by ‘random’ selection).

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_subgradient.unfold_subgradient(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 3000, tolerance: float = 1e-08, l1_penalty: float = 0.0, tv_penalty: float = 0.0, step_policy: str = 'diminishing', step_size: float = 1.0, decay: float = 1.0, polyak_margin: float = 0.05, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, variance_reduction: str = 'none', save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using projected subgradient descent.

Nonsmooth L1/TV penalties are handled natively via subgradients with Polyak / diminishing / fixed step-size policies; the best iterate by objective value is returned.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum iterations (default: 3000).

  • tolerance (float, optional) – Relative change tolerance (default: 1e-8).

  • l1_penalty (float, optional) – L1 penalty weight (default: 0.0).

  • tv_penalty (float, optional) – TV penalty weight (default: 0.0).

  • step_policy (str, optional) – 'polyak', 'diminishing' or 'fixed' (default: ‘diminishing’).

  • step_size (float, optional) – Base step size (default: 1.0).

  • decay (float, optional) – Diminishing-step decay rate (default: 1.0).

  • polyak_margin (float, optional) – Relative margin for the Polyak optimal-value estimate (default: 0.05).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • variance_reduction (str, optional) – Monte-Carlo variance reduction: 'none', 'antithetic', 'control' or 'both' (default: ‘none’).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_extragradient.unfold_extragradient(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 2000, tolerance: float = 1e-08, noise_level: float = 0.02, step_size: float | None = None, calculate_errors: bool = False, mc_noise_level: float = 0.01, n_montecarlo: int = 100, variance_reduction: str = 'none', save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Korpelevich’s extragradient method.

Solves the robust saddle formulation min_{x>=0} 1/2||Ax-b||^2 + delta*||Ax-b||_2 via its bilinear saddle form with the two-step extragradient scheme; delta = noise_level * ||b||_2 bounds the assumed measurement-noise norm.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum iterations (default: 2000).

  • tolerance (float, optional) – Relative change tolerance (default: 1e-8).

  • noise_level (float, optional) – Relative noise-ball radius (default: 0.02).

  • step_size (Optional[float], optional) – Extragradient step; auto from the Lipschitz bound when None.

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • mc_noise_level (float, optional) – Noise level for Monte-Carlo uncertainty (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • variance_reduction (str, optional) – Monte-Carlo variance reduction: 'none', 'antithetic', 'control' or 'both' (default: ‘none’).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_smt.unfold_smt(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, nonneg: bool = True, timeout_ms: int = 10000, objective: str = 'l2', calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold a neutron spectrum using an SMT solver.

Minimizes the L2 residual ||A x - b||_2 (via the exact KKT characterization of the least-squares optimum) and then the total fluence sum(x). Falls back to the L1 residual on non-converging solves.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess (accepted for API compatibility).

  • nonneg (bool, optional) – Constrain the spectrum to be non-negative (default: True).

  • timeout_ms (int, optional) – SMT solver timeout in milliseconds (default: 10000).

  • objective (str, optional) – Residual objective: 'l2' (default) or 'l1'.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default: False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default: 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default: 100.

  • save_result (bool, optional) – Save result to history, default: False.

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

Dict[str, Any]

bssunfold.core.unfold_scip.unfold_scip(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0001, norm: int = 2, timeout: float = 10.0, smoothness_order: int = 0, smoothness_weight: float = 1.0, nonneg: bool = True, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, regularization_method: str = 'manual', noise_var: float | None = None, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold a neutron spectrum using the SCIP optimizer.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess.

  • regularization (float, optional) – Regularization parameter, default: 1e-4.

  • norm (int, optional) – Norm type (1 for L1, 2 for L2), default: 2.

  • timeout (float, optional) – Time limit in seconds, default: 10.0.

  • smoothness_order (int, optional) – Smoothness constraint order (0, 1, or 2), default: 0.

  • smoothness_weight (float, optional) – Weight for the smoothness term, default: 1.0.

  • nonneg (bool, optional) – Constrain the spectrum to be non-negative, default: True.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default: False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default: 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default: 100.

  • save_result (bool, optional) – Save result to history, default: False.

  • regularization_method (str, optional) – Method for selecting the regularization parameter (‘manual’, ‘cosine’, ‘lcurve’, ‘gcv’, ‘dp’).

  • noise_var (float, optional) – Noise variance for discrepancy principle (‘dp’ method).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

Dict[str, Any]

bssunfold.core.unfold_docplex.unfold_docplex(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0001, norm: int = 2, timeout: float = 10.0, smoothness_order: int = 0, smoothness_weight: float = 1.0, nonneg: bool = True, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, regularization_method: str = 'manual', noise_var: float | None = None, random_state: int | None = None, max_neutron_energy: float | None = None) dict[str, Any][source]#

Unfold a neutron spectrum using CPLEX (docplex).

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess.

  • regularization (float, optional) – Regularization parameter, default: 1e-4.

  • norm (int, optional) – Norm type (1 for L1, 2 for L2), default: 2.

  • timeout (float, optional) – Time limit in seconds, default: 10.0.

  • smoothness_order (int, optional) – Smoothness constraint order (0, 1, or 2), default: 0.

  • smoothness_weight (float, optional) – Weight for the smoothness term, default: 1.0.

  • nonneg (bool, optional) – Constrain the spectrum to be non-negative, default: True.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty, default: False.

  • noise_level (float, optional) – Noise level for Monte-Carlo, default: 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples, default: 100.

  • save_result (bool, optional) – Save result to history, default: False.

  • regularization_method (str, optional) – Method for selecting the regularization parameter (‘manual’, ‘cosine’, ‘lcurve’, ‘gcv’, ‘dp’).

  • noise_var (float, optional) – Noise variance for discrepancy principle (‘dp’ method).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results including spectrum, residuals, and metadata.

Return type:

Dict[str, Any]

bssunfold.core.unfold_epic.unfold_epic(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, target_sigmas: ndarray | None = None, sigma_frac: float = 0.1, regularization_order: int = 1, non_neg: bool = True, noise_var: float | None = None, homogeneous_step: bool = True, regularize: dict[str, Any] | None = None, beta_shift_k: float = 0, beta_distance: float = 2, EPIC_bool: ndarray | None = None, V: ndarray | None = None, LSQpar: dict[str, Any] | None = None, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold a spectrum using EPIC Tikhonov regularization.

The EPIC weights are computed once from the response matrix and the resolved target sigmas (they do not depend on the measurements), and are reused by the Monte-Carlo uncertainty propagation.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess (unused by this method).

  • target_sigmas (np.ndarray, optional) – Target a posteriori standard deviations of the model parameters. If None, derived from sigma_frac.

  • sigma_frac (float, optional) – Fraction of the naive least-squares magnitude used to derive default target sigmas (default: 0.1).

  • regularization_order (int, optional) – Regularization operator order: 0 (identity), 1 (first derivative, default) or 2 (second derivative).

  • non_neg (bool, optional) – Apply non-negativity constraints (default: True).

  • noise_var (float, optional) – Variance of the i.i.d. misfit errors (default: None, identity Cx).

  • homogeneous_step (bool, optional) – Run a preliminary homogeneous Ch search (default: True).

  • regularize (dict, optional) – If given (can be empty), damp the EPIC weights.

  • beta_shift_k (float, optional) – Center shift for the beta bounds (default: 0).

  • beta_distance (float, optional) – Distance kept from the representability limit (default: 2).

  • EPIC_bool (np.ndarray, optional) – Boolean mask of which parameters are subject to the EPIC.

  • V (np.ndarray, optional) – Matrix mapping the searched betas to the regularization rows, beta = V @ y (shape (H.shape[0], len(y))).

  • LSQpar (dict, optional) – Tuning parameters for the nonlinear least-squares solver.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_cs.unfold_cs(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, n_atoms: int | None = None, sparsity: int | None = None, dictionary: ndarray | None = None, n_dictionary_iterations: int = 20, sigma_min: float = 0.01, sigma_decrease_factor: float = 0.5, mu_0: float = 1.0, L: int = 3, max_iterations: int = 1000, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Compressive Sensing (CS).

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • n_atoms (int, optional) – Number of dictionary atoms.

  • sparsity (int, optional) – Target sparsity for dictionary learning.

  • dictionary (np.ndarray, optional) – Pre-learned dictionary (n x n_atoms).

  • n_dictionary_iterations (int, optional) – Number of K-SVD iterations (default: 20).

  • sigma_min (float, optional) – SL0 minimum sigma (default: 0.01).

  • sigma_decrease_factor (float, optional) – SL0 sigma decrease factor (default: 0.5).

  • mu_0 (float, optional) – SL0 step-size factor (default: 1.0).

  • L (int, optional) – SL0 inner iterations per sigma (default: 3).

  • max_iterations (int, optional) – SL0 maximum outer iterations (default: 1000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_doroshenko.unfold_doroshenko(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 1000, tolerance: float = 1e-06, regularization: float = 0.0, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the Doroshenko coordinate update method.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, uniform spectrum is used.

  • max_iterations (int, optional) – Maximum number of iterations, default: 1000.

  • tolerance (float, optional) – Convergence tolerance for solution change, default: 1e-6.

  • regularization (float, optional) – Regularization strength to prevent division by zero, default: 0.0.

  • calculate_errors (bool, optional) – Flag to calculate uncertainty via Monte-Carlo, default: False.

  • noise_level (float, optional) – Noise level for Monte-Carlo uncertainty calculation, default: 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples for error estimation, default: 100.

  • save_result (bool, optional) – If True, save result to internal history, default: False.

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Dictionary containing unfolding results.

Return type:

Dict[str, Any]

bssunfold.core.unfold_directed_divergence.unfold_directed_divergence(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 200, tol_chi2: float = 1.0, tol_rel: float = 1e-06, relative_uncertainty: float = 0.05, smoothness_order: int = 0, smoothness_weight: float = 0.0, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold Bonner-sphere readings using directed divergence.

bssunfold.core.unfold_kaczmarz.unfold_kaczmarz(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 1000, omega: float = 1.0, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the Kaczmarz algorithm (ART).

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, zero spectrum is used.

  • max_iterations (int, optional) – Maximum number of iterations, default: 1000.

  • omega (float, optional) – Relaxation parameter (0 < omega <= 2), default: 1.0.

  • tolerance (float, optional) – Convergence tolerance for solution change, default: 1e-6.

  • calculate_errors (bool, optional) – Flag to calculate uncertainty via Monte-Carlo, default: False.

  • noise_level (float, optional) – Noise level for Monte-Carlo uncertainty calculation, default: 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples for error estimation, default: 100.

  • save_result (bool, optional) – If True, save result to internal history, default: False.

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Dictionary containing unfolding results.

Return type:

Dict[str, Any]

bssunfold.core.unfold_lmfit.unfold_lmfit(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, method: str = 'lbfgsb', model_name: str = 'elastic', regularization: float = 0.0001, regularization2: float = 0.0001, l1_weight: float = 0.5, regularization_method: str = 'manual', lambda_range: tuple[float, float] = (1e-06, 0.1), n_lambda: int = 30, verbose: bool = True, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using lmfit with L1/L2/Elastic regularization.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, uniform spectrum based on mean readings.

  • method (str, optional) – lmfit solver name (leastsq, lbfgsb, etc.), default: “lbfgsb”.

  • model_name (str, optional) – Regularization model: elastic, lasso, ridge, default: “elastic”.

  • regularization (float, optional) – L1 regularization strength, default: 1e-4.

  • regularization2 (float, optional) – L2 regularization strength for elastic net, default: 1e-4.

  • l1_weight (float, optional) – L1 weight for elastic net (0=pure L2, 1=pure L1), default: 0.5.

  • regularization_method (str, optional) – How to choose the regularization parameter. Options: ‘manual’ (use the supplied regularization/regularization2), or an information criterion ‘aic’, ‘aicc’ or ‘bic’. For non-manual selection the regularization parameter is swept over lambda_range and the candidate minimizing the chosen criterion is used. Default: ‘manual’.

  • lambda_range (Tuple[float, float], optional) – Log-spaced range of lambda candidates for information-criterion selection, default: (1e-6, 1e-1).

  • n_lambda (int, optional) – Number of lambda candidates for information-criterion selection, default: 30.

  • verbose (bool, optional) – Print the regularization selection summary, default: True.

  • calculate_errors (bool, optional) – Flag to calculate uncertainty via Monte-Carlo, default: False.

  • noise_level (float, optional) – Noise level for Monte-Carlo uncertainty calculation, default: 0.01.

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples for error estimation, default: 100.

  • save_result (bool, optional) – If True, save result to internal history, default: False.

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Dictionary containing unfolding results.

Return type:

Dict[str, Any]

bssunfold.core.unfold_mlem_odl.unfold_mlem_odl(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, tolerance: float = 1e-06, max_iterations: int = 1000, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold using MLEM with ODL (Operator Discretization Library).

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum approximation. If None, uniform spectrum is used.

  • tolerance (float, optional) – Convergence tolerance. Default is 1e-6.

  • max_iterations (int, optional) – Maximum number of iterations. Default is 1000.

  • calculate_errors (bool, optional) – Flag for calculating restoration errors. Default is False.

  • noise_level (float, optional) – Noise level for error calculation. Default is 0.01.

  • n_montecarlo (int, optional) – Number of Monte Carlo samples for error calculation. Default is 100.

  • save_result (bool, optional) – If True, save result to internal history. Default is False.

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Dictionary containing the spectrum restoration results.

Return type:

Dict

bssunfold.core.unfold_mlem_stop.unfold_mlem_stop(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 15000, cps_crossover: float = 30000.0, j_threshold: float | None = None, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold using MLEM-STOP algorithm with J-factor stopping criterion.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum iterations (default: 15000).

  • cps_crossover (float, optional) – Crossover CPS value for automatic J threshold (default: 30000).

  • j_threshold (float, optional) – J-factor stopping threshold. If None, computed automatically.

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_combined.unfold_combined(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], pipeline: list[dict[str, Any]], calculate_errors: bool = False, verbose: bool = True) dict[str, Any] | None[source]#

Combined unfolding method applying multiple methods sequentially.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • pipeline (List[Dict[str, Any]]) – List of methods for sequential application. Each dict should contain: - ‘method’: str - method name (e.g., ‘cvxpy’, ‘landweber’, ‘mlem’) - ‘params’: dict - parameters for the method - ‘use_as_initial’: bool (optional) - use result as initial guess - ‘store_intermediate’: bool (optional) - store intermediate result

  • calculate_errors (bool, optional) – Flag to calculate errors for the last method.

  • verbose (bool, optional) – Flag to print debug information.

Returns:

Dictionary with unfolding results.

Return type:

Dict

bssunfold.core.unfold_interpret.unfold_interpret(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0001, norm: int = 2, smoothness_order: int = 0, smoothness_weight: float = 1.0, enforce_norm: bool = False, norm_value: float = 1.0, regularization_method: str = 'manual', noise_var: float | None = None, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, tolerance: float = 1e-08, ridge_coeff: Any = 'auto', interpret_options: dict[str, Any] | None = None) dict[str, Any][source]#

Unfold and interpret a neutron spectrum with pyoptexplain.

The unfolding QP (identical to unfold_qpsolvers) is solved through pyoptexplain and the solution is interpreted. The returned dictionary is a standard bssunfold result dict with two extra keys:

  • report – Markdown interpretation report.

  • interpretation_metrics – JSON-friendly metrics dictionary.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess (used by some regularization methods).

  • regularization (float, optional) – Regularization parameter (default: 1e-4).

  • norm (int, optional) – Penalty norm, 1 or 2 (default: 2).

  • smoothness_order (int, optional) – Smoothness derivative order, 0, 1 or 2 (default: 0).

  • smoothness_weight (float, optional) – Weight of the smoothness term (default: 1.0).

  • enforce_norm (bool, optional) – Add sum(x) == norm_value (default: False).

  • norm_value (float, optional) – Target total fluence (default: 1.0).

  • regularization_method (str, optional) – Method for selecting the regularization parameter.

  • noise_var (float, optional) – Noise variance for the discrepancy principle (‘dp’ method).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • tolerance (float, optional) – Solver feasibility/optimality tolerance (default: 1e-8). Pyoptexplain’s backend may fail with iteration_limit on large problems at the strictest tolerance; relax it (e.g. 1e-5) in that case.

  • ridge_coeff (float or "auto", optional) – Diagonal ridge added to Q when norm == 1 and smoothness_order == 0 to cure rank deficiency of A'A. "auto" (default) uses 1e-8 * trace(Q) / n. Set to 0.0 to disable the ridge.

  • interpret_options (dict, optional) – Extra keyword arguments forwarded to interpret_qp().

Returns:

Standardized unfolding result plus report and interpretation_metrics keys.

Return type:

Dict[str, Any]

bssunfold.core.unfold_gravel.unfold_gravel(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, tolerance: float = 1e-08, max_iterations: int = 1000, regularization: float = 0.0, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the GRAVEL algorithm.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • tolerance (float, optional) – Convergence tolerance (default: 1e-8).

  • max_iterations (int, optional) – Maximum iterations (default: 1000).

  • regularization (float, optional) – Regularization parameter (default: 0.0).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_maxed.unfold_maxed(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, sigma_factor: float = 0.1, max_iterations: int = 5000, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the MAXED algorithm.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Reference spectrum. If None, a flat reference is used.

  • sigma_factor (float, optional) – Relative measurement uncertainty (default: 0.1). Larger values → smoother spectrum.

  • max_iterations (int, optional) – Maximum L-BFGS-B iterations (default: 5000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_tikhonov_legendre.unfold_tikhonov_legendre(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, delta: float = 0.05, n_polynomials: int = 15, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Tikhonov regularization with Legendre basis.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Not used (provided for API compatibility).

  • delta (float, optional) – Regularization parameter (default: 0.05).

  • n_polynomials (int, optional) – Number of Legendre polynomials (default: 15).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_bayes.unfold_bayes(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 4000, tolerance: float = 0.001, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Bayesian iterative unfolding.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Prior spectrum.

  • max_iterations (int, optional) – Maximum iterations (default: 4000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-3).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_bayes_spline_regularization.unfold_bayes_spline_regularization(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 4000, tolerance: float = 0.001, spline_degree: int = 3, spline_smooth: float = 0.01, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Bayes with spline regularization.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Prior spectrum.

  • max_iterations (int, optional) – Maximum iterations (default: 4000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-3).

  • spline_degree (int, optional) – Spline degree (default: 3).

  • spline_smooth (float, optional) – Spline smoothing parameter (default: 1e-2).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_statreg.unfold_statreg(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, unfoldermethod: str = 'EmpiricalBayes', regularization: float | None = None, basis_name: str = 'CubicSplines', boundary: str | None = None, derivative_degree: int = 2, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Turchin’s statistical regularisation.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • unfoldermethod (str, optional) – Regularisation method (default: 'EmpiricalBayes').

  • regularization (float, optional) – Regularisation parameter for 'User' method.

  • basis_name (str, optional) – Ignored (kept for API compatibility).

  • boundary (str, optional) – Ignored (kept for API compatibility).

  • derivative_degree (int, optional) – Derivative degree (default: 2).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_reconst.unfold_reconst(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, pp: float = 0.001, alpha: float = -1.0, beta: float = 0.0, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Turchin’s statistical regularization.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Ignored (API compatibility).

  • pp (float, optional) – PP parameter (default: 1e-3).

  • alpha (float, optional) – Regularization. <0 auto, >0 fixed (default: -1).

  • beta (float, optional) – Data fidelity. 0 auto, >0 fixed (default: 0).

  • calculate_errors (bool, optional) – Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result (default: False).

  • random_state (int, optional) – Random seed.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_scipy_direct_method.unfold_scipy_direct_method(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, tolerance: float = 1e-08, max_iterations: int = 4000, method: str = 'cg', calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using scipy direct solvers.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • tolerance (float, optional) – Solver tolerance (default: 1e-8).

  • max_iterations (int, optional) – Maximum solver iterations (default: 4000).

  • method (str, optional) – Solver method (default: ‘cg’).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_tsvd.unfold_tsvd(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, method: str = 'discrepancy', k: int | None = None, threshold: float | None = None, noise_level: float | None = None, svd_solver: str = 'full', calculate_errors: bool = False, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Truncated SVD (TSVD).

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • method (str, optional) – K-selection method (default: ‘discrepancy’).

  • k (int, optional) – Fixed truncation parameter.

  • threshold (float, optional) – Threshold ratio for truncation.

  • noise_level (float, optional) – Noise level estimate.

  • svd_solver (str, optional) – SVD backend: 'full' (default), 'arpack' or 'propack'.

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_lanczos.unfold_lanczos(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization_method: str = 'gcv', max_iterations: int | None = None, regularization: float = 1e-08, noise_level: float | None = None, calculate_errors: bool = False, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold a neutron spectrum with the Lanczos-hybrid (Krylov) method.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess (accepted for API compatibility).

  • regularization_method (str, optional) – Method for selecting the regularization parameter. Only 'gcv' is supported (default: ‘gcv’).

  • max_iterations (int, optional) – Maximum Krylov dimension. Defaults to min(n_detectors, n_energy_bins).

  • regularization (float, optional) – Fallback regularization parameter (default: 1e-8).

  • noise_level (float, optional) – Relative noise level used for discrepancy-principle early stopping.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty (default: False).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_cgls.unfold_cgls(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 100, tolerance: float = 1e-12, noise_level: float | None = None, regularization: float = 0.0, smoothness_order: int = 0, calculate_errors: bool = False, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold a neutron spectrum with the CGLS method.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess.

  • max_iterations (int, optional) – Maximum number of iterations (default: 100).

  • tolerance (float, optional) – Relative tolerance on the normal-equation residual (default: 1e-12).

  • noise_level (float, optional) – Relative noise level used for discrepancy-principle stopping.

  • regularization (float, optional) – Tikhonov regularization parameter (default: 0.0).

  • smoothness_order (int, optional) – Derivative order of the regularization operator L used when regularization is positive (default: 0).

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty (default: False).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_gks.unfold_gks(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, smoothness_order: int = 0, regularization_method: str = 'gcv', max_iterations: int | None = None, regularization: float = 1e-08, noise_level: float | None = None, calculate_errors: bool = False, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold a neutron spectrum with the Generalized Krylov Subspace method.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess (accepted for API compatibility).

  • smoothness_order (int, optional) – Derivative order of the regularization operator L (default: 0).

  • regularization_method (str, optional) – Method for selecting the regularization parameter: 'gcv', 'dp', 'lcurve' or 'manual' (default: ‘gcv’).

  • max_iterations (int, optional) – Maximum Krylov dimension. Defaults to min(n_detectors, n_energy_bins).

  • regularization (float, optional) – Manual/fallback regularization parameter (default: 1e-8).

  • noise_level (float, optional) – Relative noise level used by the Discrepancy Principle.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty (default: False).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_tikhonov_tv.unfold_tikhonov_tv(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, epsilon: float | None = None, mu: tuple[float, float, float] = (1.0, 1.0, 1.0), max_iterations: int = 100, type_: str = 'TT', beta: float = 1.0, zthr: float = 2.5, tolerance: float = 0.0001, noise_level: float | None = None, calculate_errors: bool = False, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold a neutron spectrum with noise-constrained Tikhonov-TV.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess (accepted for API compatibility).

  • epsilon (float, optional) – (Estimate of) the squared 2-norm of the noise. If None, derived from noise_level ((noise_level * ||b||)^2) or from the residuals of an unregularized least-squares solve.

  • mu (tuple, optional) – Penalty parameters (mu1, mu2, mu3) (default: (1.0, 1.0, 1.0)).

  • max_iterations (int, optional) – Maximum number of ADMM iterations (default: 100).

  • type (str, optional) – Optimization problem: 'TT', 'TV' or 'T' (default: ‘TT’).

  • beta (float, optional) – Balancing parameter between TV and Tikhonov terms, or 'adapt' for adaptive estimation (default: 1.0).

  • zthr (float, optional) – Threshold for the adaptive beta estimation (default: 2.5).

  • tolerance (float, optional) – Stabilization stopping criterion (default: 1e-4).

  • noise_level (float, optional) – Relative noise level used to derive a default epsilon.

  • calculate_errors (bool, optional) – If True, calculate Monte-Carlo uncertainty (default: False).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_sandii.unfold_sandii(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 50, tolerance: float = 0.001, chi_fac: int = 1, relative_uncertainty: float = 0.1, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the SAND-II algorithm.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • max_iterations (int, optional) – Maximum number of iterations (default: 50).

  • tolerance (float, optional) – Maximum relative spectrum change used when chi_fac=0 (default: 1e-3).

  • chi_fac (int, optional) – Convergence criterion (default: 1, chi-square based).

  • relative_uncertainty (float, optional) – Relative measurement uncertainty for the chi-square criterion (default: 0.1).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_crystal_ball.unfold_crystal_ball(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, regularization: float = 0.0, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the CRYSTAL BALL algorithm.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Unused; accepted for interface uniformity.

  • regularization (float, optional) – Tikhonov regularization strength for the Gram-matrix inversion (default: 0.0).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_rfsp_jul.unfold_rfsp_jul(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 200, tolerance: float = 0.0001, weights: ndarray | None = None, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the RFSP-JUL algorithm.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • max_iterations (int, optional) – Maximum number of iterations (default: 200).

  • tolerance (float, optional) – Convergence tolerance on maximum relative spectrum change (default: 1e-4).

  • weights (np.ndarray, optional) – Per-detector weights for the residual term. None => equal weights.

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_staysl.unfold_staysl(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, relative_uncertainty: float = 0.1, prior_uncertainty: float = 1.0, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the STAY’SL Bayesian algorithm.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Prior spectrum guess. If None, a flat spectrum is used as the prior mean.

  • relative_uncertainty (float, optional) – Relative measurement uncertainty for Cb (default: 0.1).

  • prior_uncertainty (float, optional) – Relative prior uncertainty for Cx (default: 1.0).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_express.unfold_express(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, n_groups: int = 6, interval_boundaries: ndarray | None = None, max_iterations: int = 3, tol_iteration: float = 0.05, relative_uncertainty: float = 0.05, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold Bonner-sphere readings with a piecewise-exponential model.

bssunfold.core.unfold_bunki.unfold_bunki(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, smoothing: float = 0.1, max_iterations: int = 1000, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the BUNKI (SPUNIT) algorithm.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • smoothing (float, optional) – Three-point smoothing factor (default: 0.1).

  • max_iterations (int, optional) – Maximum number of iterations (default: 1000).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_bunkiut.unfold_bunkiut(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, smoothing: float = 0.05, max_iterations: int = 1000, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the BUNKI-UT (BON31G) algorithm.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • smoothing (float, optional) – Three-point smoothing factor (default: 0.05).

  • max_iterations (int, optional) – Maximum number of iterations (default: 1000).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_osem.unfold_osem(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 50, n_subsets: int = 1, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the OSEM algorithm.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • max_iterations (int, optional) – Maximum number of iterations (default: 50).

  • n_subsets (int, optional) – Number of ordered subsets over the detector readings (default: 1, i.e. standard MLEM).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_osem_anlm.unfold_osem_anlm(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 50, n_subsets: int = 1, tolerance: float = 1e-06, h: float | None = None, search_window: int = 11, similarity_window: int = 3, alpha: float = 1.0, anlm_mode: str = 'subset', log_space: bool = True, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the OSEM-ANLM algorithm.

Ordered-subset expectation maximisation with asymptotic non-local means regularization (Jamaati et al. 2026, https://doi.org/10.1038/s41598-026-70607-1), adapted to Bonner sphere spectra: the ANLM filter is applied to the intermediate spectrum after every OSEM subset update (anlm_mode="subset") or once to the OSEM result (anlm_mode="post").

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • max_iterations (int, optional) – Maximum number of iterations (default: 50).

  • n_subsets (int, optional) – Number of ordered subsets over the detector readings (default: 1, i.e. standard MLEM with per-iteration ANLM).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

  • h (float, optional) – Noise level for the ANLM filter. If None (default), it is estimated automatically from the intermediate spectra.

  • search_window (int, optional) – ANLM search window N (default: 11, article optimum).

  • similarity_window (int, optional) – ANLM similarity (patch) window nu (default: 3, article optimum).

  • alpha (float, optional) – Spread of the Gaussian kernel over the similarity window (default: 1.0).

  • anlm_mode (str, optional) – 'subset' — ANLM after every subset update (default, article pseudo-code); 'post' — single ANLM application to the OSEM result.

  • log_space (bool, optional) – Apply the ANLM filter to the logarithm of the spectrum (default: True, scale-free for spectra spanning orders of magnitude). See anlm_filter_1d().

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_louhi.unfold_louhi(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, smoothness: float = 1.0, smooth_order: int = 1, auto_smooth: bool = False, chi2_target: float | None = None, max_iterations: int = 500, tolerance: float = 1e-06, relative_uncertainty: float = 0.1, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, variance_reduction: str = 'none', save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the LOUHI78 algorithm.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Default (a-priori) spectrum. If None, a flat spectrum is used.

  • smoothness (float, optional) – Smoothing weight lambda (default: 1.0).

  • smooth_order (int, optional) – Smoothing operator order 0/1/2 (default: 1, first differences).

  • auto_smooth (bool, optional) – Adjust the smoothing weight automatically to reach chi2_target (default: False).

  • chi2_target (Optional[float], optional) – Target data chi-square for auto_smooth (default: number of detectors).

  • max_iterations (int, optional) – Maximum number of Hildreth sweeps (default: 500).

  • tolerance (float, optional) – Relative objective change per sweep for convergence (default: 1e-6).

  • relative_uncertainty (float, optional) – Relative measurement uncertainty (default: 0.1).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • variance_reduction (str, optional) – MC variance reduction: ‘none’, ‘antithetic’, ‘control’, ‘both’ (default: ‘none’).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_mapem.unfold_mapem(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, prior: str = 'quadratic', beta: float = 0.001, prior_delta: float = 1.0, gamma: float = 1.0, max_iterations: int = 50, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using penalised EM (MAP-EM).

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • prior (str, optional) – Prior type: 'none', 'quadratic', 'logcosh' or 'relative_difference' (default: 'quadratic').

  • beta (float, optional) – Prior weight (default: 1e-3).

  • prior_delta (float, optional) – Width parameter of the quadratic/logcosh priors and additive floor of the relative-difference prior (default: 1.0).

  • gamma (float, optional) – Edge-preservation parameter of the relative-difference prior (default: 1.0).

  • max_iterations (int, optional) – Maximum number of iterations (default: 50).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_bsrem.unfold_bsrem(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, prior: str = 'none', beta: float = 0.001, prior_delta: float = 1.0, gamma: float = 1.0, max_iterations: int = 50, n_subsets: int = 1, tolerance: float = 1e-06, relaxation: float | Callable[[int], float] | None = None, addition_after_iteration: float = 0.0001, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the BSREM algorithm.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • prior (str, optional) – Prior type: 'none', 'quadratic', 'logcosh' or 'relative_difference' (default: 'none').

  • beta (float, optional) – Prior weight (default: 1e-3).

  • prior_delta (float, optional) – Width parameter of the quadratic/logcosh priors and additive floor of the relative-difference prior (default: 1.0).

  • gamma (float, optional) – Edge-preservation parameter of the relative-difference prior (default: 1.0).

  • max_iterations (int, optional) – Maximum number of iterations (default: 50).

  • n_subsets (int, optional) – Number of ordered subsets over the detector readings (default: 1).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

  • relaxation (float or callable, optional) – Relaxation sequence (default: None -> constant 1).

  • addition_after_iteration (float, optional) – Floor value for spectrum bins (default: 1e-4).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_sart.unfold_sart(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 50, tolerance: float = 1e-06, relaxation: float | Callable[[int], float] | None = None, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the SART algorithm.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • max_iterations (int, optional) – Maximum number of iterations (default: 50).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

  • relaxation (float or callable, optional) – Relaxation sequence (default: None -> constant 0.8).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_ferdor.unfold_ferdor(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 100, tolerance: float = 0.001, smoothing: float = 0.001, chi_squared_target: float = 1.0, relative_uncertainty: float = 0.1, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the FERDOR algorithm.

Parameters:
  • detector_names (list[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray | None, optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • max_iterations (int, optional) – Maximum number of smoothing-weight iterations (default: 100).

  • tolerance (float, optional) – Relative tolerance on the reduced chi-square (default: 1e-3).

  • smoothing (float, optional) – Initial smoothing weight alpha (default: 1e-3).

  • chi_squared_target (float, optional) – Target reduced chi-square per degree of freedom (default: 1.0).

  • relative_uncertainty (float, optional) – Relative measurement uncertainty for the chi-square criterion (default: 0.1).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

dict[str, Any]

bssunfold.core.unfold_rebunki.unfold_rebunki(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, smoothing: float = 0.1, max_iterations: int = 1000, tolerance: float = 0.01, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the ReBUNKI (SPUNIT) algorithm.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, a flat spectrum is used.

  • smoothing (float, optional) – Three-point smoothing factor (default: 0.1).

  • max_iterations (int, optional) – Maximum number of iterations (default: 1000).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 0.01).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_nsduaz.unfold_nsduaz(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, catalogue: dict[str, ndarray] | None = None, use_catalogue: bool = True, reference_name: str | None = None, smoothing: float = 0.1, max_iterations: int = 1000, tolerance: float = 0.01, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the NSDUAZ algorithm.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Explicit initial spectrum guess. When given, it overrides the catalogue selection.

  • catalogue (Optional[Dict[str, np.ndarray]], optional) – User-supplied catalogue of candidate initial spectra (label -> spectrum on the detector energy grid). When None, the built-in mini-catalogue is used.

  • use_catalogue (bool, optional) – If True (default), the initial spectrum is selected from the catalogue when initial_spectrum is not provided; if False, a flat spectrum is used (NSDUAZ “flat spectrum” mode).

  • reference_name (str, optional) – Reference sphere name for the catalogue statistical test (default: auto-detect 20.32 cm sphere).

  • smoothing (float, optional) – Three-point smoothing factor (default: 0.1).

  • max_iterations (int, optional) – Maximum number of iterations (default: 1000).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 0.01).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_parametric.unfold_parametric(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, initial_params: dict[str, float] | None = None, method: str = 'leastsq', optimizer: str = 'lmfit', alpha: float = 0.0001, alpha_auto: bool = False, solver_backend: str = 'auto', max_iter: int = 50, tol: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the FRUIT-based parametric method.

The spectrum is modelled as a weighted superposition of thermal, epithermal and fast components (Bedogni FRUIT / Pyshkina B3S).

The optimizer parameter selects the backend:

  • "lmfit" – classic lmfit least-squares (default).

  • "cvxpy" – sequential QP via cvxpy (SQP).

  • "qpsolvers" – sequential QP via qpsolvers (SQP).

  • "combined" – lmfit first, then QP refinement.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid in MeV.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (unused in parametric method).

  • initial_params (Optional[Dict[str, float]], optional) – Initial parameter values for the parametric model. Keys: b, beta_prime, alpha, beta, P_th, P_epi.

  • method (str, optional) – lmfit solver method (default: “leastsq”).

  • optimizer (str, optional) – Backend optimizer: “lmfit”, “cvxpy”, “qpsolvers”, or “combined” (default: “lmfit”).

  • alpha (float, optional) – Regularization weight for QP-based optimizers (default: 1e-4). Also used as initial alpha for lmfit when alpha_auto is True.

  • alpha_auto (bool, optional) – If True, select alpha automatically via GCV for the lmfit optimizer (default: False).

  • solver_backend (str, optional) – QP solver backend string: “auto”, “cvxpy”, “cvxpy:ECOS”, “qpsolvers”, “qpsolvers:osqp”, etc. (default: “auto”).

  • max_iter (int, optional) – Max SQP iterations for cvxpy/qpsolvers (default: 50).

  • tol (float, optional) – Convergence tolerance for SQP (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_parametric.solve_parametric_cvxpy(A_matrix, b_readings, E, log_steps, initial_params=None, alpha=0.0001, solver_backend='auto', max_iter=50, tol=1e-06)[source]#

Solve parametric unfolding via sequential QP using cvxpy.

The nonlinear parametric model is linearized at each iteration and the resulting QP is solved with cvxpy, including parameter bounds and a Tikhonov penalty on the parameter update.

Parameters:
  • A_matrix (np.ndarray) – Response matrix (n_detectors x n_energy).

  • b_readings (np.ndarray) – Measured readings (n_detectors,).

  • E (np.ndarray) – Energy grid in MeV.

  • log_steps (np.ndarray) – Logarithmic energy steps (d(ln E)).

  • initial_params (dict, optional) – Initial parameter values.

  • alpha (float, optional) – Regularization weight for parameter penalty (default: 1e-4).

  • solver_backend (str, optional) – CVXPY solver backend: “auto”, “cvxpy”, or “cvxpy:ECOS” etc. (default: “auto”).

  • max_iter (int, optional) – Maximum SQP iterations (default: 50).

  • tol (float, optional) – Convergence tolerance on parameter update norm (default: 1e-6).

Returns:

(spectrum, success, message, nfev)

Return type:

Tuple[np.ndarray, bool, str, int]

bssunfold.core.unfold_parametric.solve_parametric_qpsolvers(A_matrix, b_readings, E, log_steps, initial_params=None, alpha=0.0001, solver_backend='auto', max_iter=50, tol=1e-06)[source]#

Solve parametric unfolding via sequential QP using qpsolvers.

The nonlinear parametric model is linearized at each iteration and the resulting QP is solved with qpsolvers, including parameter bounds and a Tikhonov penalty on the parameter update.

Parameters:
  • A_matrix (np.ndarray) – Response matrix (n_detectors x n_energy).

  • b_readings (np.ndarray) – Measured readings (n_detectors,).

  • E (np.ndarray) – Energy grid in MeV.

  • log_steps (np.ndarray) – Logarithmic energy steps (d(ln E)).

  • initial_params (dict, optional) – Initial parameter values.

  • alpha (float, optional) – Regularization weight (default: 1e-4).

  • solver_backend (str, optional) – QP solver backend: “auto”, “qpsolvers”, or “qpsolvers:osqp” etc. (default: “auto”).

  • max_iter (int, optional) – Maximum SQP iterations (default: 50).

  • tol (float, optional) – Convergence tolerance on parameter update norm (default: 1e-6).

Returns:

(spectrum, success, message, nfev)

Return type:

Tuple[np.ndarray, bool, str, int]

bssunfold.core.unfold_parametric.solve_parametric_combined(A_matrix, b_readings, E, log_steps, initial_params=None, method='leastsq', alpha=0.0001, solver_backend='auto')[source]#

Solve parametric unfolding: lmfit first, then QP refinement.

  1. Use lmfit to find the best-fit parametric shape parameters.

  2. Take the resulting spectrum as a starting point and refine it with a QP solver (cvxpy or qpsolvers) that adds non-negativity and a penalty toward the lmfit solution.

Parameters:
  • A_matrix (np.ndarray) – Response matrix (n_detectors x n_energy).

  • b_readings (np.ndarray) – Measured readings (n_detectors,).

  • E (np.ndarray) – Energy grid in MeV.

  • log_steps (np.ndarray) – Logarithmic energy steps (d(ln E)).

  • initial_params (dict, optional) – Initial parameter values for lmfit.

  • method (str, optional) – lmfit method (default: “leastsq”).

  • alpha (float, optional) – Regularization weight for QP refinement (default: 1e-4).

  • solver_backend (str, optional) – QP backend for refinement: “auto”, “cvxpy”, “qpsolvers”, etc. (default: “auto”).

Returns:

(spectrum, success, message, nfev)

Return type:

Tuple[np.ndarray, bool, str, int]

bssunfold.core.unfold_parametric2.unfold_parametric2(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, optimizer: str = 'grid', b_range: tuple[float, float, int] = (0.5, 2.0, 5), Tf_range: tuple[float, float, int] = (0.5, 10.0, 5), c_range: tuple[float, float, int] = (0.5, 3.0, 4), alpha: float = 0.0001, solver_backend: str = 'auto', max_iter_qp: int = 50, tol_qp: float = 1e-06, noise_level: float = 0.05, max_iter: int = 200, tol_chi2: float = 1.0, calculate_errors: bool = False, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the BON95 parametric method.

Uses the four-component parameterization from Sannikov BON95: thermal (Maxwellian), epithermal (1/E), intermediate, and fast (evaporation/cascade) components. After parametric fitting, the result is refined by directed-divergence iterations.

The optimizer parameter selects the parametric fit backend:

  • "grid" – grid search + NLS (default, no extra deps).

  • "cvxpy" – SQP via cvxpy.

  • "qpsolvers" – SQP via qpsolvers.

  • "combined" – grid search + SQP refinement.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid in MeV.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (unused in parametric method).

  • optimizer (str) – Parametric fit optimizer (default: “grid”).

  • b_range (tuple) – Grid range for b: (min, max, n_points). Used by “grid”/”combined”.

  • Tf_range (tuple) – Grid range for Tf (MeV): (min, max, n_points). Used by “grid”/”combined”.

  • c_range (tuple) – Grid range for c: (min, max, n_points). Used by “grid”/”combined”.

  • alpha (float) – Tikhonov regularization for SQP (default: 1e-4).

  • solver_backend (str) – QP backend for SQP (default: “auto”).

  • max_iter_qp (int) – Max SQP iterations (default: 50).

  • tol_qp (float) – SQP convergence tolerance (default: 1e-6).

  • noise_level (float) – Relative uncertainty for measurements (default: 0.05 = 5%).

  • max_iter (int) – Max directed-divergence iterations (default: 200).

  • tol_chi2 (float) – Chi-squared convergence threshold (default: 1.0).

  • calculate_errors (bool) – Calculate Monte-Carlo errors (default: False).

  • n_montecarlo (int) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_parametric2.solve_parametric2(A_matrix: ndarray, b_readings: ndarray, E: ndarray, ln_steps: ndarray, b_meas: ndarray | None = None, optimizer: str = 'grid', b_range: tuple[float, float, int] = (0.5, 2.0, 5), Tf_range: tuple[float, float, int] = (0.5, 10.0, 5), c_range: tuple[float, float, int] = (0.5, 3.0, 4), alpha: float = 0.0001, solver_backend: str = 'auto', max_iter_qp: int = 50, tol_qp: float = 1e-06, max_iter: int = 200, tol_chi2: float = 1.0) tuple[ndarray, bool, str, int][source]#

Solve unfolding using the full BON95 parametric pipeline.

  1. Parametric fit using the selected optimizer.

  2. Directed-divergence iteration refinement.

Parameters:
  • A_matrix (np.ndarray) – Response matrix (n_det x n_energy).

  • b_readings (np.ndarray) – Measured readings (n_det,).

  • E (np.ndarray) – Energy grid in MeV.

  • ln_steps (np.ndarray) – Logarithmic bin widths.

  • b_meas (np.ndarray, optional) – Measurement uncertainties for weighted NLS.

  • optimizer (str) – Parametric fit optimizer (default: “grid”): - "grid" – grid search + NLS (default, no extra deps). - "cvxpy" – SQP via cvxpy. - "qpsolvers" – SQP via qpsolvers. - "combined" – grid search + SQP refinement.

  • b_range (tuple) – Grid search ranges for shape parameters (used by “grid” and “combined”).

  • Tf_range (tuple) – Grid search ranges for shape parameters (used by “grid” and “combined”).

  • c_range (tuple) – Grid search ranges for shape parameters (used by “grid” and “combined”).

  • alpha (float) – Tikhonov regularization for SQP optimizers (default: 1e-4).

  • solver_backend (str) – QP backend for SQP optimizers (default: “auto”).

  • max_iter_qp (int) – Max SQP iterations for QP-based optimizers (default: 50).

  • tol_qp (float) – SQP convergence tolerance (default: 1e-6).

  • max_iter (int) – Max directed-divergence iterations (default: 200).

  • tol_chi2 (float) – Chi-squared convergence threshold (default: 1.0).

Returns:

(spectrum, success, message, nfev)

Return type:

Tuple[np.ndarray, bool, str, int]

bssunfold.core.unfold_parametric2.solve_bon95_parametric(A_matrix: ndarray, b_readings: ndarray, E: ndarray, ln_steps: ndarray, b_range: tuple[float, float, int] = (0.5, 2.0, 5), Tf_range: tuple[float, float, int] = (0.5, 10.0, 5), c_range: tuple[float, float, int] = (0.5, 3.0, 4), b_meas: ndarray | None = None, top_n: int = 5) tuple[dict[str, float], float, list[dict[str, float]]][source]#

Grid search + NLS for the BON95 parametric model.

Scans over (b, Tf, c) shape parameters, solves for optimal linear coefficients (a1..a4) at each grid point via weighted NLS, and returns the best result.

Parameters:
  • A_matrix (np.ndarray) – Response matrix (n_det x n_energy).

  • b_readings (np.ndarray) – Measured readings (n_det,).

  • E (np.ndarray) – Energy grid in MeV.

  • ln_steps (np.ndarray) – Logarithmic bin widths.

  • b_range (tuple) – (min, max, n_points) for each shape parameter.

  • Tf_range (tuple) – (min, max, n_points) for each shape parameter.

  • c_range (tuple) – (min, max, n_points) for each shape parameter.

  • b_meas (np.ndarray, optional) – Measurement uncertainties (sigma_i). Used as weights.

  • top_n (int) – Number of top candidates to return.

Returns:

(best_params, best_chi2, top_candidates) best_params keys: b, Tf, c, a1, a2, a3, a4

Return type:

Tuple[dict, float, list]

bssunfold.core.unfold_parametric2.directed_divergence_iteration(A_matrix: ndarray, b_readings: ndarray, E: ndarray, ln_steps: ndarray, phi0: ndarray, b_meas: ndarray | None = None, max_iter: int = 200, tol_chi2: float = 1.0, tol_rel: float = 1e-06) tuple[ndarray, int, float, bool][source]#

Refine spectrum via directed-divergence (I-divergence) iterations.

Multiplicative update rule (Itakura-Saito / Csiszar-Tusnady):

phi_{k+1}(E_j) = phi_k(E_j) * numerator / denominator

where:

numerator = sum_i [ A_i(E_j) * M_i / M_p_i ] denominator = sum_i [ A_i(E_j) ]

and M_p_i = sum_j A_i(E_j) * phi_k(E_j) * d(ln E)_j is the computed reading for detector i.

Parameters:
  • A_matrix (np.ndarray) – Response matrix (n_det x n_energy).

  • b_readings (np.ndarray) – Measured readings (n_det,).

  • E (np.ndarray) – Energy grid in MeV.

  • ln_steps (np.ndarray) – Logarithmic bin widths.

  • phi0 (np.ndarray) – Initial spectrum guess (n_energy,).

  • b_meas (np.ndarray, optional) – Measurement uncertainties. If None, uniform weights.

  • max_iter (int) – Maximum iterations (default: 200).

  • tol_chi2 (float) – Stop when chi2 < tol_chi2 (default: 1.0).

  • tol_rel (float) – Stop when relative change in spectrum < tol_rel (default: 1e-6).

Returns:

(spectrum, n_iterations, final_chi2, converged)

Return type:

Tuple[np.ndarray, int, float, bool]

bssunfold.core.unfold_parametric2.solve_bon95_cvxpy(A_matrix: ndarray, b_readings: ndarray, E: ndarray, ln_steps: ndarray, b_meas: ndarray | None = None, initial_params: dict[str, float] | None = None, alpha: float = 0.0001, solver_backend: str = 'auto', max_iter: int = 50, tol: float = 1e-06) tuple[ndarray, bool, str, int][source]#

Solve BON95 parametric fitting via sequential QP using cvxpy.

Optimizes shape parameters (b, Tf, c) via SQP. At each iteration, the nonlinear model is linearized w.r.t. shape params and the resulting QP is solved with cvxpy. The linear coefficients (a1..a4) are re-solved by NLS at each step.

Parameters:
  • A_matrix (np.ndarray) – Response matrix (n_det x n_energy).

  • b_readings (np.ndarray) – Measured readings (n_det,).

  • E (np.ndarray) – Energy grid in MeV.

  • ln_steps (np.ndarray) – Logarithmic bin widths.

  • b_meas (np.ndarray, optional) – Measurement uncertainties for weighting.

  • initial_params (dict, optional) – Starting shape params {b, Tf, c}. If None, grid scan is used.

  • alpha (float) – Tikhonov regularization weight (default: 1e-4).

  • solver_backend (str) – CVXPY solver backend (default: “auto”).

  • max_iter (int) – Maximum SQP iterations (default: 50).

  • tol (float) – Convergence tolerance on parameter update norm (default: 1e-6).

Returns:

(spectrum, success, message, nfev)

Return type:

Tuple[np.ndarray, bool, str, int]

bssunfold.core.unfold_parametric2.solve_bon95_qpsolvers(A_matrix: ndarray, b_readings: ndarray, E: ndarray, ln_steps: ndarray, b_meas: ndarray | None = None, initial_params: dict[str, float] | None = None, alpha: float = 0.0001, solver_backend: str = 'auto', max_iter: int = 50, tol: float = 1e-06) tuple[ndarray, bool, str, int][source]#

Solve BON95 parametric fitting via sequential QP using qpsolvers.

Same algorithm as solve_bon95_cvxpy but uses qpsolvers backends (OSQP, ECOS, etc.).

Parameters:
  • A_matrix (np.ndarray) – Response matrix (n_det x n_energy).

  • b_readings (np.ndarray) – Measured readings (n_det,).

  • E (np.ndarray) – Energy grid in MeV.

  • ln_steps (np.ndarray) – Logarithmic bin widths.

  • b_meas (np.ndarray, optional) – Measurement uncertainties for weighting.

  • initial_params (dict, optional) – Starting shape params {b, Tf, c}.

  • alpha (float) – Tikhonov regularization weight (default: 1e-4).

  • solver_backend (str) – QP solver backend (default: “auto”).

  • max_iter (int) – Maximum SQP iterations (default: 50).

  • tol (float) – Convergence tolerance (default: 1e-6).

Returns:

(spectrum, success, message, nfev)

Return type:

Tuple[np.ndarray, bool, str, int]

bssunfold.core.unfold_parametric2.solve_bon95_combined(A_matrix: ndarray, b_readings: ndarray, E: ndarray, ln_steps: ndarray, b_meas: ndarray | None = None, alpha: float = 0.0001, solver_backend: str = 'auto', max_iter_qp: int = 50, tol_qp: float = 1e-06) tuple[ndarray, bool, str, int][source]#

Solve BON95: grid search first, then SQP refinement.

  1. Grid search for best starting (b, Tf, c).

  2. SQP refinement via cvxpy or qpsolvers.

Parameters:
  • A_matrix (as usual.)

  • b_readings (as usual.)

  • E (as usual.)

  • ln_steps (as usual.)

  • b_meas (np.ndarray, optional) – Measurement uncertainties.

  • alpha (float) – Tikhonov regularization for SQP (default: 1e-4).

  • solver_backend (str) – QP backend: “auto”, “cvxpy:ECOS”, “qpsolvers:osqp”, etc.

  • max_iter_qp (int) – Max SQP iterations (default: 50).

  • tol_qp (float) – SQP convergence tolerance (default: 1e-6).

Returns:

(spectrum, success, message, nfev)

Return type:

Tuple[np.ndarray, bool, str, int]

bssunfold.core.unfold_fruit_like.unfold_fruit_like(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, initial_params: dict[str, float] | None = None, method: str = 'leastsq', calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using FRUIT-like parametric method.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid in MeV.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (unused in parametric method).

  • initial_params (Optional[Dict[str, float]], optional) – Initial parameter values for the parametric model.

  • method (str, optional) – lmfit solver method (default: “leastsq”).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_hybrid_parametric.unfold_hybrid_parametric(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, refinement_method: str = 'landweber', max_iterations: int = 100, tolerance: float = 1e-06, step_size: float = 0.01, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using hybrid parametric-nonparametric method.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid in MeV.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • refinement_method (str, optional) – Refinement method: “landweber” or “mlem” (default: “landweber”).

  • max_iterations (int, optional) – Maximum iterations (default: 100).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

  • step_size (float, optional) – Step size for Landweber (default: 0.01).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_bayesian_parametric.unfold_bayesian_parametric(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, sigma: float = 0.02, n_samples: int = 1000, burn_in: int = 200, proposal_scale: float = 0.1, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Bayesian parametric method.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid in MeV.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess (unused).

  • sigma (float, optional) – Measurement uncertainty (default: 0.02).

  • n_samples (int, optional) – Number of MCMC samples (default: 1000).

  • burn_in (int, optional) – Burn-in samples (default: 200).

  • proposal_scale (float, optional) – Proposal scale (default: 0.1).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_imaxed.unfold_imaxed(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, sigma_factor: float = 0.1, max_iterations: int = 5000, tolerance: float = 1e-08, line_search_tol: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the IMAXED algorithm.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Reference spectrum. If None, a flat reference is used.

  • sigma_factor (float, optional) – Relative measurement uncertainty (default: 0.1).

  • max_iterations (int, optional) – Maximum Newton iterations (default: 5000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-8).

  • line_search_tol (float, optional) – Line search tolerance (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_amaxed.unfold_amaxed(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, sigma_factor: float = 0.1, target_chi2: float | None = None, max_iterations: int = 5000, tolerance: float = 1e-08, line_search_tol: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the AMAXED algorithm.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Reference spectrum. If None, a flat reference is used.

  • sigma_factor (float, optional) – Relative measurement uncertainty (default: 0.1).

  • target_chi2 (float, optional) – Target chi-squared value. If None, automatically determined.

  • max_iterations (int, optional) – Maximum Newton iterations (default: 5000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-8).

  • line_search_tol (float, optional) – Line search tolerance (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_amaxed_regularization.unfold_amaxed_regularization(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, sigma_factor: float = 0.1, tau: float = 1.0, max_iterations: int = 5000, tolerance: float = 1e-08, line_search_tol: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the AMAXED-Regularization algorithm.

This method combines the advantages of AMAXED with Tikhonov regularization, providing stable convergence without requiring manual chi-squared tuning.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Reference spectrum. If None, a flat reference is used.

  • sigma_factor (float, optional) – Relative measurement uncertainty (default: 0.1).

  • tau (float, optional) – Regularization parameter (default: 1.0). Larger values favor solutions closer to the prior.

  • max_iterations (int, optional) – Maximum Newton iterations (default: 5000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-8).

  • line_search_tol (float, optional) – Line search tolerance (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_fista.unfold_fista(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback: Callable | None = None, readings: dict[str, float] | None = None, initial_spectrum: ndarray | None = None, max_iterations: int = 500, tolerance: float = 1e-08, regularization: float = 0.0, l1_penalty: float = 0.0, tv_penalty: float = 0.0, nonnegativity: bool = True, x_min: float = 0.0, x_max: float = inf, noise_level: float | None = None, eta: float = 1.01, calculate_errors: bool = False, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using FISTA algorithm.

The Fast Iterative Shrinkage-Thresholding Algorithm (FISTA) is an accelerated proximal gradient method that achieves O(1/k^2) convergence rate for convex optimization problems. It can handle L1 regularization (sparsity), TV regularization, and box constraints.

Parameters:
  • detector_names (List[str]) – Names of detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid in MeV.

  • sensitivities (Dict[str, np.ndarray]) – Sensitivity matrix as dictionary.

  • cc_icrp116 (Dict[str, np.ndarray]) – Dose conversion coefficients.

  • save_result_callback (callable, optional) – Callback to save results.

  • readings (Dict[str, float], optional) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial guess for spectrum.

  • max_iterations (int, optional) – Maximum number of iterations (default: 500).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-8).

  • regularization (float, optional) – Tikhonov regularization parameter (default: 0.0).

  • l1_penalty (float, optional) – L1 regularization penalty parameter for sparsity (default: 0.0).

  • tv_penalty (float, optional) – Total variation penalty parameter (default: 0.0).

  • nonnegativity (bool, optional) – Apply nonnegativity constraints (default: True).

  • x_min (float, optional) – Lower bound for solution (default: 0.0).

  • x_max (float, optional) – Upper bound for solution (default: inf).

  • noise_level (float, optional) – Relative noise level for discrepancy principle stopping.

  • eta (float, optional) – Safety factor for discrepancy principle (default: 1.01).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_hybrid_gmres.unfold_hybrid_gmres(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback: Callable | None = None, readings: dict[str, float] | None = None, initial_spectrum: ndarray | None = None, max_iterations: int = 100, regularization_method: str = 'gcv', regularization: float = 0.0, noise_level: float | None = None, eta: float = 1.01, reorthogonalization: bool = True, calculate_errors: bool = False, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Hybrid GMRES method.

The hybrid GMRES method combines the GMRES iterative solver with Tikhonov regularization applied to the projected problem at each iteration. The regularization parameter is selected automatically using GCV or discrepancy principle.

Parameters:
  • detector_names (List[str]) – Names of detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid in MeV.

  • sensitivities (Dict[str, np.ndarray]) – Sensitivity matrix as dictionary.

  • cc_icrp116 (Dict[str, np.ndarray]) – Dose conversion coefficients.

  • save_result_callback (callable, optional) – Callback to save results.

  • readings (Dict[str, float], optional) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial guess for spectrum.

  • max_iterations (int, optional) – Maximum Krylov dimension (default: 100).

  • regularization_method (str, optional) – Method for selecting regularization parameter: ‘gcv’, ‘modgcv’, ‘discrep’ (default: ‘gcv’).

  • regularization (float, optional) – Fixed regularization parameter (used if not auto-selected).

  • noise_level (float, optional) – Relative noise level for discrepancy principle.

  • eta (float, optional) – Safety factor for discrepancy principle (default: 1.01).

  • reorthogonalization (bool, optional) – Apply full reorthogonalization (default: True).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_mcmc.unfold_mcmc(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, sigma_prior: float = 0.05, lambda_prior: float = 0.5, lengthscale: float = 3.0, n_samples: int = 2000, tune: int = 1000, chains: int = 2, target_accept: float = 0.95, use_hierarchical: bool = False, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, progressbar: bool = False) dict[str, Any][source]#

Unfold neutron spectrum using Bayesian MCMC with NUTS sampler.

This method implements a full Bayesian approach to neutron spectrum unfolding using Markov Chain Monte Carlo (MCMC) methods. Unlike traditional methods that provide only point estimates, MCMC generates samples from the full posterior distribution, enabling comprehensive uncertainty quantification.

The implementation uses the No-U-Turn Sampler (NUTS), an adaptive variant of Hamiltonian Monte Carlo (HMC) that automatically tunes its parameters for efficient sampling.

Key Features#

  1. Uncertainty Quantification: Provides 95% credible intervals (HPD) for each energy bin, showing where the spectrum is well-constrained vs uncertain.

  2. Automatic Regularization: Through the log-space smoothness prior, the method keeps the underdetermined solution positive and smooth without the collapse seen with independent per-bin priors.

  3. Convergence Diagnostics: Built-in R-hat and effective sample size (ESS) metrics ensure reliable posterior estimates.

Methodology#

The Bayesian model is defined as:

  • Likelihood: b ~ Normal(A @ f, sigma) where b is measured readings, A is response matrix, f is spectrum

  • Prior: f = exp(theta) with theta ~ MvNormal(mu_prior, s * C_ou), where mu_prior is the log of the data-driven prior center (non-negative least-squares solution or user initial_spectrum), C_ou is the OU correlation exp(-|i-j|/lengthscale), and s ~ HalfNormal(lambda_prior).

  • Hyperpriors (optional): when use_hierarchical=True the relative likelihood noise is estimated as rel_noise ~ HalfNormal(sigma_prior).

param detector_names:

Names of available detectors.

type detector_names:

List[str]

param n_energy_bins:

Number of energy bins.

type n_energy_bins:

int

param E_MeV:

Energy grid in MeV.

type E_MeV:

np.ndarray

param sensitivities:

Detector sensitivity arrays.

type sensitivities:

Dict[str, np.ndarray]

param cc_icrp116:

ICRP-116 conversion coefficients for dose calculation.

type cc_icrp116:

Dict[str, np.ndarray]

param save_result_callback:

Callback function to save result to history.

type save_result_callback:

callable

param readings:

Detector readings (counts or count rates).

type readings:

Dict[str, float]

param initial_spectrum:

Prior center guess for the spectrum. When None, the non-negative least-squares solution of A @ x = b is used as the prior center.

type initial_spectrum:

Optional[np.ndarray], optional

param sigma_prior:

Relative likelihood noise scale (default: 0.05). With use_hierarchical=False the noise is fixed at sigma_prior * |b|; with use_hierarchical=True it is the prior scale of the estimated relative noise.

type sigma_prior:

float, optional

param lambda_prior:

Prior scale of the log-spectrum spatial amplitude (default: 0.5).

type lambda_prior:

float, optional

param lengthscale:

OU smoothness correlation length in energy bins (default: 3.0).

type lengthscale:

float, optional

param n_samples:

Number of MCMC samples per chain after tuning (default: 2000).

type n_samples:

int, optional

param tune:

Number of tuning (warmup) samples per chain (default: 1000).

type tune:

int, optional

param chains:

Number of independent MCMC chains (default: 2).

type chains:

int, optional

param target_accept:

Target acceptance rate for NUTS (default: 0.95).

type target_accept:

float, optional

param use_hierarchical:

Estimate the likelihood noise from the data (default: False).

type use_hierarchical:

bool, optional

param calculate_errors:

Calculate additional Monte-Carlo errors (default: False).

type calculate_errors:

bool, optional

param noise_level:

Noise level for additional Monte-Carlo (default: 0.01).

type noise_level:

float, optional

param n_montecarlo:

Number of additional Monte-Carlo samples (default: 100).

type n_montecarlo:

int, optional

param save_result:

Save result to history (default: False).

type save_result:

bool, optional

param random_state:

Random seed for reproducibility.

type random_state:

int, optional

param progressbar:

Show sampling progress bar (default: False).

type progressbar:

bool, optional

returns:

Unfolding results dictionary containing:

  • ‘energy’: Energy grid (MeV)

  • ‘spectrum’: Mean posterior spectrum

  • ‘spectrum_absolute’: Same as spectrum (for API consistency)

  • ‘spectrum_uncertainty’: Standard deviation of posterior

  • ‘spectrum_lower’: Lower bound of 95% HPD interval

  • ‘spectrum_upper’: Upper bound of 95% HPD interval

  • ‘effective_readings’: Computed readings from posterior mean

  • ‘residual’: Difference between measured and computed readings

  • ‘residual_norm’: L2 norm of residual

  • ‘method’: ‘MCMC’

  • ‘doserates’: Dose rates calculated from spectrum

  • ‘mcmc_stats’: Dictionary with MCMC-specific information (samples, median, HPD bounds, rhat, ess, trace and sampling metadata)

rtype:

Dict[str, Any]

raises ImportError:

If PyMC or ArviZ is not installed.

raises RuntimeError:

If MCMC sampling fails to converge.

Examples

>>> from bssunfold import Detector
>>> detector = Detector()
>>> readings = {'sphere_1': 100.5, 'sphere_2': 85.3, ...}
>>> result = detector.unfold_mcmc(
...     readings,
...     n_samples=2000,
...     chains=2,
...     use_hierarchical=True,
...     progressbar=True,
... )
>>> spectrum_mean = result['spectrum']
>>> spectrum_std = result['spectrum_uncertainty']
>>> rhat = result['mcmc_stats']['rhat']
>>> print(f"Max R-hat: {rhat.max():.3f}")  # Should be < 1.1

See also

unfold_bayes

Bayesian iterative unfolding (D’Agostini)

unfold_bayesian_parametric

Bayesian parametric model with MCMC

bssunfold.core.unfold_cuqi.unfold_cuqi(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, sampler: str = 'pcn', noise_level: float = 0.05, prior: str = 'gmrf', gmrf_order: int = 1, lengthscale: float = 3.0, prec: float = 1.0, hierarchical: bool | None = None, delta_alpha: float = 1.0, delta_beta: float = 0.0001, n_samples: int = 2000, n_burnin: int = 1000, thin: int = 1, chains: int = 2, scale: float | None = None, max_depth: int = 8, step_size: float | None = None, credible_level: float = 95.0, calculate_errors: bool = False, mc_noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, progressbar: bool = False) dict[str, Any][source]#

Unfold neutron spectrum using CUQIpy Bayesian samplers.

This is the workflow-level wrapper (same contract as bssunfold.core.unfold_mcmc.unfold_mcmc()) around solve_cuqi_bayesian(). It builds the system matrix from the detector readings, runs the requested CUQIpy MCMC sampler(s) on the log-scale Bayesian model and returns the standardized unfolding result enriched with posterior samples, credible intervals and convergence diagnostics.

Supported samplers: 'pcn', 'cwmh', 'nuts', 'mala', 'ula', 'gibbs' (hierarchical, data-driven smoothing) and 'gibbs_nuts'.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid in MeV.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients for dose calculation.

  • save_result_callback (callable) – Callback function to save result to history.

  • readings (Dict[str, float]) – Detector readings (counts or count rates).

  • initial_spectrum (Optional[np.ndarray], optional) – Prior center guess for the spectrum. When None, the non-negative least-squares solution of A @ x = b is used as the prior center.

  • sampler (str, optional) – CUQIpy sampler (default: 'pcn').

  • noise_level (float, optional) – Relative likelihood noise scale (default: 0.05).

  • prior (str, optional) – Log-spectrum prior: 'gmrf' (default) or 'ou'.

  • gmrf_order (int, optional) – GMRF operator order, 1 or 2 (default: 1).

  • lengthscale (float, optional) – OU correlation length in energy bins (default: 3.0).

  • prec (float, optional) – Fixed prior precision scale (default: 1.0); inferred from the data by the hierarchical Gibbs samplers.

  • hierarchical (bool, optional) – Force the hierarchical Gibbs scheme (default: derived from sampler).

  • delta_alpha (float, optional) – Gamma hyperprior shape (default: 1.0).

  • delta_beta (float, optional) – Gamma hyperprior rate (default: 1e-4).

  • n_samples (int, optional) – Posterior samples per chain (default: 2000).

  • n_burnin (int, optional) – Warmup iterations per chain (default: 1000). Increase for the Langevin samplers ('mala'/'ula').

  • thin (int, optional) – Thinning interval (default: 1).

  • chains (int, optional) – Number of independent chains (default: 2).

  • scale (float, optional) – Proposal step size (default: per-sampler _DEFAULT_SCALES).

  • max_depth (int, optional) – NUTS maximum tree depth (default: 8).

  • step_size (float, optional) – NUTS leapfrog step size (default: None, tuned by CUQIpy).

  • credible_level (float, optional) – Credible mass (%) of the HPD interval (default: 95).

  • calculate_errors (bool, optional) – Calculate additional Monte-Carlo errors (default: False).

  • mc_noise_level (float, optional) – Noise level for the additional Monte-Carlo loop (default: 0.01).

  • n_montecarlo (int, optional) – Number of additional Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • progressbar (bool, optional) – Present for API consistency (default: False).

Returns:

Standardized unfolding result with the usual keys (energy, spectrum, effective_readings, residual, residual_norm, method, doserates) plus spectrum_uncertainty, spectrum_lower, spectrum_upper and cuqi_stats (posterior samples, ESS, R-hat, acceptance rate, hyperparameter draws and sampling metadata).

Return type:

Dict[str, Any]

Raises:
  • ImportError – If CUQIpy is not installed.

  • RuntimeError – If MCMC sampling fails.

Examples

>>> from bssunfold import Detector
>>> detector = Detector()
>>> result = detector.unfold_cuqi(
...     readings,
...     sampler='gibbs_nuts',
...     n_samples=1000,
...     n_burnin=500,
...     chains=2,
... )
>>> spectrum = result['spectrum']
>>> acc = result['cuqi_stats']['acc_rate']

See also

unfold_mcmc

PyMC/NUTS Bayesian unfolding

unfold_bayes

Bayesian iterative unfolding (D’Agostini)

bssunfold.core.unfold_cuqi.solve_cuqi_bayesian(A_matrix: ndarray, b_readings: ndarray, E: ndarray | None = None, log_steps: ndarray | None = None, sampler: str = 'pcn', noise_level: float = 0.05, prior: str = 'gmrf', gmrf_order: int = 1, lengthscale: float = 3.0, prec: float = 1.0, hierarchical: bool | None = None, delta_alpha: float = 1.0, delta_beta: float = 0.0001, n_samples: int = 2000, n_burnin: int = 1000, thin: int = 1, chains: int = 2, scale: float | None = None, max_depth: int = 8, step_size: float | None = None, credible_level: float = 95.0, initial_spectrum: ndarray | None = None, random_state: int | None = None, progressbar: bool = False) tuple[ndarray, dict[str, Any]][source]#

Solve the unfolding problem with CUQIpy Bayesian samplers.

The spectrum is modelled on the log scale f = exp(theta) with a smoothness prior centered on a data-driven guess (the non-negative least-squares solution of A @ x = b, or the user-supplied initial_spectrum) and a Gaussian likelihood with relative noise sigma = noise_level * |b|.

Priors#

  • prior='gmrf' (default): theta ~ GMRF(mu, prec) — CUQIpy finite-difference precision operator, gmrf_order = 1 or 2.

  • prior='ou': theta ~ Gaussian(mu, C_ou / prec) — dense Ornstein-Uhlenbeck correlation with lengthscale bins.

Samplers#

'pcn', 'cwmh', 'nuts', 'mala', 'ula' sample the fixed-precision posterior; 'gibbs' and 'gibbs_nuts' sample the hierarchical model where the GMRF precision has a Gamma hyperprior (delta ~ Gamma(delta_alpha, delta_beta)) and is inferred jointly with the spectrum. Hierarchical sampling requires the 'gmrf' prior.

Internally each sampler uses the statistically equivalent formulation in which it mixes best on the severely ill-conditioned unfolding posterior: PCN/CWMH sample the centered log-spectrum theta - mu (required for the correct pCN proposal scaling), MALA/ULA are automatically Laplace-whitened around a Gauss-Newton MAP estimate, and NUTS and the Gibbs samplers use the native CUQIpy model.

param A_matrix:

Response matrix (n_detectors x n_energy).

type A_matrix:

np.ndarray

param b_readings:

Measured readings (n_detectors,).

type b_readings:

np.ndarray

param E:

Energy grid in MeV (unused by the model, kept for API consistency).

type E:

np.ndarray, optional

param log_steps:

Logarithmic energy steps (unused by the model, kept for API consistency; the forward model follows the package convention b = A @ spectrum).

type log_steps:

np.ndarray, optional

param sampler:

CUQIpy sampler: 'pcn', 'cwmh', 'ula', 'mala', 'nuts', 'gibbs' or 'gibbs_nuts' (default: 'pcn').

type sampler:

str, optional

param noise_level:

Relative measurement noise scale (default: 0.05); the likelihood standard deviation is noise_level * |b|.

type noise_level:

float, optional

param prior:

Log-spectrum prior: 'gmrf' (default) or 'ou'.

type prior:

str, optional

param gmrf_order:

Order of the GMRF finite-difference operator, 1 or 2 (default: 1). Higher order yields smoother spectra.

type gmrf_order:

int, optional

param lengthscale:

OU correlation length in energy bins for prior='ou' (default: 3).

type lengthscale:

float, optional

param prec:

Prior precision scale for theta (default: 1.0). Ignored by the hierarchical Gibbs samplers, which infer it from the data.

type prec:

float, optional

param hierarchical:

Convenience switch: when True the Gibbs samplers are used. If None (default) it is derived from sampler.

type hierarchical:

bool, optional

param delta_alpha:

Shape of the Gamma hyperprior on the GMRF precision (default: 1.0).

type delta_alpha:

float, optional

param delta_beta:

Rate of the Gamma hyperprior on the GMRF precision (default: 1e-4).

type delta_beta:

float, optional

param n_samples:

Number of posterior samples per chain (default: 2000).

type n_samples:

int, optional

param n_burnin:

Number of warmup/tuning iterations per chain (default: 1000). Increase (e.g. 3000+) for the Langevin samplers 'mala'/'ula'.

type n_burnin:

int, optional

param thin:

Thinning interval kept between stored samples (default: 1).

type thin:

int, optional

param chains:

Number of independent chains (default: 2).

type chains:

int, optional

param scale:

Proposal step size. Defaults depend on the sampler (see _DEFAULT_SCALES); for the whitened Langevin samplers the scale is in whitened units.

type scale:

float, optional

param max_depth:

Maximum tree depth for NUTS (default: 8).

type max_depth:

int, optional

param step_size:

Fixed leapfrog step size for NUTS; None lets CUQIpy tune it during warmup (default: None).

type step_size:

float, optional

param credible_level:

Credible mass (%) of the reported HPD interval (default: 95).

type credible_level:

float, optional

param initial_spectrum:

Prior center guess (n_energy,). When None, the non-negative least-squares solution is used as the center.

type initial_spectrum:

np.ndarray, optional

param random_state:

Random seed for reproducibility.

type random_state:

int, optional

param progressbar:

Present for API consistency; CUQIpy progress bars are controlled via the TQDM_DISABLE environment variable (default: False).

type progressbar:

bool, optional

returns:
  • spectrum: Mean posterior spectrum (n_energy,)

  • stats: Dictionary with ‘samples’ (linear scale, chains * n_samples x n_energy), ‘theta_samples’, ‘mean’, ‘median’, ‘std’, ‘hpd_lower’/’hpd_upper’ (HPD interval), ‘ess’, ‘rhat’ (chains > 1), ‘acc_rate’, ‘delta_samples’ (hierarchical samplers), and sampling metadata (‘sampler’, ‘prior’, ‘n_chains’, …).

rtype:

Tuple[np.ndarray, Dict[str, Any]]

raises ImportError:

If CUQIpy is not installed.

raises ValueError:

If sampler or prior is unknown, or an invalid combination is requested.

bssunfold.core.unfold_zfit.unfold_zfit(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 100, use_mcmc: bool = False, n_samples: int = 1000, regularization: float = 0.1, smoothness_weight: float = 0.01, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold using zfit Bayesian inference.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum approximation.

  • max_iterations (int, optional) – Maximum iterations (default: 100).

  • use_mcmc (bool, optional) – Use MCMC sampling (default: False).

  • n_samples (int, optional) – Number of MCMC samples (default: 1000).

  • regularization (float, optional) – Regularization strength (default: 0.1).

  • smoothness_weight (float, optional) – Smoothness prior weight (default: 0.01).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for error calculation (default: 0.01).

  • n_montecarlo (int, optional) – Number of MC samples (default: 100).

  • save_result (bool, optional) – Save to history (default: False).

  • random_state (int, optional) – Random seed.

Returns:

Unfolding results dictionary.

Return type:

Dict

bssunfold.core.unfold_qubo.unfold_qubo(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, n_bits: int = 6, max_value: float | None = None, regularization: float = 0.01, max_iterations: int = 1000, annealing_time: int = 1000, num_reads: int = 10, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 50, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold using QUBO formulation with quantum-inspired annealing.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum approximation.

  • n_bits (int, optional) – Bits per energy bin (default: 6).

  • max_value (float, optional) – Maximum spectrum value for scaling.

  • regularization (float, optional) – Regularization parameter (default: 0.01).

  • max_iterations (int, optional) – Maximum iterations (default: 1000).

  • annealing_time (int, optional) – Annealing sweeps (default: 1000).

  • num_reads (int, optional) – Number of independent reads (default: 10).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for error calculation (default: 0.01).

  • n_montecarlo (int, optional) – Number of MC samples (default: 50).

  • save_result (bool, optional) – Save to history (default: False).

  • random_state (int, optional) – Random seed.

Returns:

Unfolding results dictionary.

Return type:

Dict

bssunfold.core.unfold_maeo.unfold_maeo(detector: Any, readings: dict[str, float], n_cycles: int = 20, n_gen_per_cycle: int = 10, pop_size: int = 100, algorithms: list[str] | None = None, lambda_smooth: float = 0.01, prior_spectrum: ndarray | None = None, initial_spectrum: ndarray | None = None, convergence_assist_ratio: float = 0.2, seed: int | None = None, verbose: bool = False, **kwargs) dict[str, Any][source]#

Unfold neutron spectrum using MAEO ensemble optimization.

This is the high-level interface for MAEO unfolding that integrates with the Detector class.

Parameters:
  • detector (Detector) – Detector instance with response matrix and energy grid.

  • readings (dict) – Dictionary mapping detector names to measured count rates.

  • n_cycles (int, optional) – Number of MAEO cycles (default: 20).

  • n_gen_per_cycle (int, optional) – Generations per cycle (default: 10).

  • pop_size (int, optional) – Population size per island (default: 100).

  • algorithms (list of str, optional) – Algorithms to use as islands. Default: [“nsga3”, “ctaea”, “agemoea2”, “spea2”].

  • lambda_smooth (float, optional) – Smoothness regularization weight (default: 0.01).

  • prior_spectrum (np.ndarray, optional) – Prior/guess spectrum for additional objective.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum for warm-start.

  • convergence_assist_ratio (float, optional) – Fraction of cycles for convergence phase (default: 0.2).

  • seed (int, optional) – Random seed for reproducibility.

  • verbose (bool, optional) – Print progress information (default: False).

  • **kwargs – Additional keyword arguments.

Returns:

Standardized result dictionary with spectrum, dose rates, etc.

Return type:

dict

See also

solve_maeo

Low-level solver function.

unfold_maeo_ensemble

Variant with explicit ensemble control.

Examples

>>> from bssunfold import Detector
>>> detector = Detector()
>>> readings = {
...     'sphere_1': 100.5,
...     'sphere_2': 85.3,
...     'sphere_3': 72.1,
...     'sphere_4': 58.9,
...     'sphere_5': 45.2,
...     'sphere_6': 32.8,
... }
>>> result = detector.unfold_maeo(readings, n_cycles=15, verbose=True)
>>> print(f"Spectrum integral: {np.sum(result['spectrum']):.2f}")
>>> print(f"Best algorithm: {result.get('best_algorithm', 'N/A')}")
bssunfold.core.unfold_odl_advanced.unfold_odl_pdhg(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 100, tau: float | None = None, sigma: float | None = None, use_tv: bool = True, tv_weight: float = 0.1, nonnegativity: bool = True, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold using ODL PDHG with TV regularization.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum approximation.

  • max_iterations (int, optional) – Maximum number of iterations (default: 100).

  • tau (float, optional) – Primal step size.

  • sigma (float, optional) – Dual step size.

  • use_tv (bool, optional) – Use Total Variation regularization (default: True).

  • tv_weight (float, optional) – TV regularization weight (default: 0.1).

  • nonnegativity (bool, optional) – Enforce non-negativity (default: True).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for error calculation (default: 0.01).

  • n_montecarlo (int, optional) – Number of MC samples (default: 100).

  • save_result (bool, optional) – Save to history (default: False).

  • random_state (int, optional) – Random seed.

Returns:

Unfolding results dictionary.

Return type:

Dict

bssunfold.core.unfold_odl_advanced.unfold_odl_douglas_rachford(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 100, use_tv: bool = True, tv_weight: float = 0.1, nonnegativity: bool = True, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold using ODL Douglas-Rachford splitting with TV regularization.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum approximation.

  • max_iterations (int, optional) – Maximum number of iterations (default: 100).

  • use_tv (bool, optional) – Use Total Variation regularization (default: True).

  • tv_weight (float, optional) – TV regularization weight (default: 0.1).

  • nonnegativity (bool, optional) – Enforce non-negativity (default: True).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for error calculation (default: 0.01).

  • n_montecarlo (int, optional) – Number of MC samples (default: 100).

  • save_result (bool, optional) – Save to history (default: False).

  • random_state (int, optional) – Random seed.

Returns:

Unfolding results dictionary.

Return type:

Dict

bssunfold.core.unfold_cascade.unfold_cascade(detector, readings: dict[str, float], cascade_stages: list[CascadeStage] | None = None, calculate_errors: bool = False, verbose: bool = True, save_result: bool = False, multi_resolution: bool = False, coarse_bins: int | None = None) dict[str, Any][source]#

Perform cascade unfolding with sequential method refinement.

This function applies unfolding methods in sequence, where each method can use the result of the previous method as: 1. Initial guess (use_as_initial=True) 2. Prior/reference spectrum (use_as_prior=True for the bayes* family) 3. Regularization target

The cascade can stop early when a stage reaches quality_threshold.

Parameters:
  • detector (Detector) – Configured Bonner-sphere detector.

  • readings (Dict[str, float]) – Detector readings.

  • cascade_stages (List[CascadeStage], optional) – Configuration for cascade stages. Defaults to create_default_cascade("general").

  • calculate_errors (bool) – Whether to calculate errors (only for final stage).

  • verbose (bool) – Print progress information.

  • save_result (bool) – Persist each stage’s result to the detector history.

  • multi_resolution (bool) – If True, run the first stage on a coarse energy grid and use its prolongated solution as the initial guess for the fine-grid stages. This stabilises ill-conditioned high-resolution inversions by resolving the low-frequency shape first.

  • coarse_bins (int, optional) – Coarse-grid resolution for multi_resolution. Defaults to max(8, n_energy_bins // 8).

Returns:

Result dictionary with the final spectrum and metadata (stages_run, method_sequence, convergence_history, quality_metrics, intermediate_results, status, message).

Return type:

dict

bssunfold.core.unfold_composite.unfold_composite(detector, readings: dict[str, float], n_methods: int = 5, timeout_per_method: float = 30.0, save_result: bool = False, spectrum: ndarray | None = None, energy: ndarray | None = None, method_names: list[str] | None = None, ensemble_weights: dict[str, float] | None = None) dict[str, Any][source]#

Run an adaptive ensemble of unfolding methods and combine results.

Parameters:
  • detector (Detector) – Configured Bonner-sphere detector.

  • readings (Dict[str, float]) – Detector readings.

  • n_methods (int) – Maximum number of methods to combine.

  • timeout_per_method (float) – Wall-clock timeout per individual method (seconds).

  • save_result (bool) – Persist each method’s result to the detector history.

  • spectrum (np.ndarray, optional) – Reference/estimated spectrum used to select the method pool by hardness. If omitted, a general robust pool is used.

  • energy (np.ndarray, optional) – Energy grid for spectrum. Defaults to detector.E_MeV.

  • method_names (list, optional) – Explicit list of method short names to run (overrides selection).

  • ensemble_weights (dict, optional) – Per-method base weights (defaults to DEFAULT_ENSEMBLE_WEIGHTS).

Returns:

Result dictionary with the combined spectrum and metadata (successful_methods, consistency, weights, individual_spectra, status, message).

Return type:

dict

bssunfold.core.unfold_binned.unfold_binned(detector, readings: dict[str, float], bin_lookup: dict[str, Any] | None = None, lookup_path: str | Path | None = None, timeout_per_method: float = 30.0, save_result: bool = False, **kwargs: Any) dict[str, Any][source]#

Bin-wise adaptive unfolding: best method per energy bin.

Parameters:
  • detector (Detector) – Configured Bonner-sphere detector.

  • readings (Dict[str, float]) – Detector readings.

  • bin_lookup (dict, optional) – Pre-computed lookup table. If None, loaded from lookup_path (or the built-in default).

  • lookup_path (str or Path, optional) – Path to a JSON lookup file. Ignored when bin_lookup is provided.

  • timeout_per_method (float) – Wall-clock timeout per individual method (seconds).

  • save_result (bool) – Persist result to detector history.

Returns:

Standard bssunfold result dict with extra keys method_map, successful_methods, individual_spectra.

Return type:

dict

bssunfold.core.unfold_ensemble.unfold_ensemble(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, methods: list[tuple[Callable, dict[str, Any]]] | None = None, weights: ndarray | None = None, combination: str = 'weighted_average', trim_fraction: float = 0.2, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using ensemble method.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess.

  • methods (list of (callable, dict), optional) – Solver functions and their keyword arguments.

  • weights (np.ndarray, optional) – Per-method weights for weighted average.

  • combination (str, optional) – Combination strategy (default: 'weighted_average').

  • trim_fraction (float, optional) – Trim fraction for trimmed mean (default: 0.2).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_iterative_refinement.unfold_iterative_refinement(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, first_pass_kwargs: dict[str, Any] | None = None, second_pass_kwargs: dict[str, Any] | None = None, alpha: float | None = None, max_alpha_search: int = 20, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using iterative refinement.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess.

  • first_pass_kwargs (dict, optional) – Keyword arguments for first-pass solver.

  • second_pass_kwargs (dict, optional) – Keyword arguments for second-pass solver.

  • alpha (float, optional) – Blending factor (None = auto-select).

  • max_alpha_search (int, optional) – Number of alpha candidates for line search (default: 20).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

bssunfold.core.unfold_randomized_kaczmarz.unfold_randomized_kaczmarz(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, max_iterations: int = 1000, omega: float = 1.0, tolerance: float = 1e-06, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using the Randomized Kaczmarz algorithm.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess. If None, zero spectrum is used.

  • max_iterations (int, optional) – Maximum number of iterations (default: 1000).

  • omega (float, optional) – Relaxation parameter (default: 1.0).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

  • calculate_errors (bool, optional) – Calculate uncertainty via Monte-Carlo (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Dictionary containing unfolding results.

Return type:

Dict[str, Any]

bssunfold.core.unfold_eki.unfold_eki(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback, readings: dict[str, float], initial_spectrum: ndarray | None = None, n_ensemble: int = 50, n_iterations: int = 50, regularization: float = 0.0001, inflation: float = 1.02, noise_std: float | None = None, calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None) dict[str, Any][source]#

Unfold neutron spectrum using Ensemble Kalman Inversion.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray) – Energy grid.

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback to save result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (Optional[np.ndarray], optional) – Initial spectrum guess.

  • n_ensemble (int, optional) – Number of ensemble members (default: 50).

  • n_iterations (int, optional) – Number of EKI iterations (default: 50).

  • regularization (float, optional) – Regularization for covariance stability (default: 1e-4).

  • inflation (float, optional) – Covariance inflation factor (default: 1.02).

  • noise_std (float, optional) – Measurement noise std (default: None = auto).

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Dictionary containing unfolding results.

Return type:

Dict[str, Any]

bssunfold.core.unfold_nnksvd.unfold_nnksvd(detector_names: list[str], n_energy_bins: int, E_MeV: ndarray, sensitivities: dict[str, ndarray], cc_icrp116: dict[str, ndarray], save_result_callback: Callable[[dict[str, Any]], str], readings: dict[str, float], initial_spectrum: ndarray | None = None, n_atoms: int = 15, sparsity: int = 2, dictionary: ndarray | None = None, training_signals: ndarray | None = None, n_dictionary_iterations: int = 80, lambda_tik: float = 0.01, prior_wt: float = 0.5, sparse_coder: str = 'nnls_topk', calculate_errors: bool = False, noise_level: float = 0.01, n_montecarlo: int = 100, save_result: bool = False, random_state: int | None = None, tolerance: float = 1e-06, n_nnls_iter: int | None = None) dict[str, Any][source]#

Detector-level wrapper for the non-negative K-SVD unfolding method.

See solve_nnksvd_unfold() for the algorithmic details; this function adapts the solver to the bssunfold.core._base_unfolder.run_unfolding() workflow so that it integrates transparently with bssunfold.Detector.

Parameters:
  • detector_names (List[str]) – Names of available detectors.

  • n_energy_bins (int) – Number of energy bins.

  • E_MeV (np.ndarray, optional) – Energy grid (MeV).

  • sensitivities (Dict[str, np.ndarray]) – Detector sensitivity arrays.

  • cc_icrp116 (Dict[str, np.ndarray]) – ICRP-116 conversion coefficients.

  • save_result_callback (callable) – Callback used to save the result to history.

  • readings (Dict[str, float]) – Detector readings.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum guess.

  • n_atoms (int, optional) – Number of dictionary atoms (default: 15).

  • sparsity (int, optional) – Target sparsity K (default: 2).

  • dictionary (np.ndarray, optional) – Pre-learned non-negative dictionary (n x p).

  • training_signals (np.ndarray, optional) – Training signals for online K-SVD (n x m). If not provided, log-spaced Gaussian bumps on the energy grid are used.

  • n_dictionary_iterations (int, optional) – K-SVD iterations (default: 80).

  • lambda_tik (float, optional) – Tikhonov regularization weight (default: 0.01).

  • prior_wt (float, optional) – Training-sample-driven prior weight (default: 0.5).

  • sparse_coder (str, optional) – Sparse-coding strategy (default: "nnls_topk").

  • calculate_errors (bool, optional) – Calculate Monte-Carlo errors (default: False).

  • noise_level (float, optional) – Noise level for Monte-Carlo (default: 0.01).

  • n_montecarlo (int, optional) – Number of Monte-Carlo samples (default: 100).

  • save_result (bool, optional) – Save result to history (default: False).

  • random_state (int, optional) – Random seed for reproducibility.

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

  • n_nnls_iter (int, optional) – Maximum NNLS iterations.

  • E_MeV – Energy grid in MeV. Passed through to solve_nnksvd_unfold() for log-spaced Gaussian training signal generation. When None, the energy grid stored in the E_MeV parameter of this function (the detector grid) is used.

Returns:

Unfolding results dictionary.

Return type:

Dict[str, Any]

Core Functions#

Underlying solver functions:

bssunfold.core.unfold_cvxpy.solve_cvxpy(A: ndarray, b: ndarray, alpha: float, norm: int = 2, solver: str = 'ECOS', x0: ndarray | None = None, ub: ndarray | None = None) ndarray[source]#

Solve unfolding problem using cvxpy.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • alpha (float) – Regularization parameter.

  • norm (int, optional) – Norm type (1 for L1, 2 for L2).

  • solver (str, optional) – CVXPY solver name.

  • x0 (np.ndarray, optional) – Not used (provided for API compatibility).

Returns:

Unfolded spectrum (n,).

Return type:

np.ndarray

bssunfold.core.unfold_landweber.solve_landweber(A: ndarray, b: ndarray, x0: ndarray, max_iterations: int = 1000, tolerance: float = 1e-06) tuple[ndarray, int, bool][source]#

Solve unfolding problem using Landweber iteration.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial guess (n,).

  • max_iterations (int, optional) – Maximum iterations (default: 1000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

Returns:

Tuple of (solution, iterations, converged).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_mlem.solve_mlem(A: ndarray, b: ndarray, x0: ndarray, max_iterations: int = 1000, tolerance: float = 1e-06) tuple[ndarray, int, bool][source]#

Solve unfolding problem using MLEM iteration.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial guess (n,).

  • max_iterations (int, optional) – Maximum iterations (default: 1000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

Returns:

Tuple of (solution, iterations, converged).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_mlem_stop.solve_mlem_stop(A: ndarray, b: ndarray, x0: ndarray, max_iterations: int = 15000, cps_crossover: float = 30000.0, j_threshold: float | None = None) tuple[ndarray, int, bool][source]#

Solve unfolding problem using MLEM with J-factor stopping criterion.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial guess (n,).

  • max_iterations (int, optional) – Maximum iterations (default: 15000).

  • cps_crossover (float, optional) – Crossover CPS value for automatic J threshold (default: 30000). Used only when j_threshold is None.

  • j_threshold (float, optional) – J-factor stopping threshold. If None, computed as mean(b) / cps_crossover.

Returns:

Tuple of (solution, iterations, converged).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_qpsolvers.solve_qpsolvers(A: ndarray, b: ndarray, alpha: float, norm: int = 2, solver: str = 'osqp', x0: ndarray | None = None, smoothness_order: int = 0, smoothness_weight: float = 1.0, ub: ndarray | None = None) ndarray | None[source]#

Solve unfolding problem using qpsolvers.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • alpha (float) – Regularization parameter.

  • norm (int, optional) – Norm type (1 for L1, 2 for L2).

  • solver (str, optional) – QP solver name (default: ‘osqp’).

  • x0 (np.ndarray, optional) – Initial values.

  • smoothness_order (int, optional) – Smoothness constraint order (0, 1, or 2).

  • smoothness_weight (float, optional) – Weight for smoothness term.

Returns:

Unfolded spectrum or None if solving failed.

Return type:

Optional[np.ndarray]

bssunfold.core.unfold_mystic.solve_mystic(A: ndarray, b: ndarray, alpha: float, norm: int = 2, solver: str = 'fmin_powell', x0: ndarray | None = None, maxiter: int | None = None, maxfun: int | None = None, smoothness_order: int = 0, smoothness_weight: float = 1.0, E_MeV: ndarray | None = None, max_neutron_energy: float | None = None) ndarray[source]#

Solve unfolding problem using mystic.

Minimizes ||A x - b||^2 + alpha * ||x||_norm with the non-negativity constraint x >= 0 imposed via a quadratic penalty.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • alpha (float) – Regularization parameter.

  • norm (int, optional) – Norm type (1 for L1, 2 for L2).

  • solver (str, optional) – Mystic solver name: ‘fmin’, ‘fmin_powell’, ‘diffev’ or ‘diffev2’ (default: ‘fmin_powell’).

  • x0 (np.ndarray, optional) – Initial values. Defaults to the zero vector.

  • maxiter (int, optional) – Maximum number of solver iterations.

  • maxfun (int, optional) – Maximum number of function evaluations.

  • smoothness_order (int, optional) – Smoothness constraint order (0, 1, or 2).

  • smoothness_weight (float, optional) – Weight for the smoothness term.

Returns:

Unfolded spectrum (n,). Returns a zero vector if solving failed.

Return type:

np.ndarray

bssunfold.core.unfold_mystic.solve_mystic_hybrid(A: ndarray, b: ndarray, alpha: float, norm: int = 2, x0: ndarray | None = None, global_solver: str = 'diffev2', local_solver: str = 'fmin_powell', global_maxiter: int | None = None, global_maxfun: int | None = None, local_maxiter: int | None = None, local_maxfun: int | None = None, npop: int | None = None, smoothness_order: int = 0, smoothness_weight: float = 1.0, E_MeV: ndarray | None = None, max_neutron_energy: float | None = None) ndarray[source]#

Two-stage hybrid solver: global search then local refinement.

Stage 1 runs a population-based solver (default diffev2) with automatically derived bounds to locate the basin of the global minimum. Stage 2 feeds that result as x0 into a local direct-search solver (default fmin_powell) for precise convergence.

This combines the robustness of global exploration with the accuracy of local optimization, which is a widely used practical strategy for ill-posed inverse problems like spectrum unfolding.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • alpha (float) – Regularization parameter.

  • norm (int, optional) – Norm type (1 for L1, 2 for L2), default: 2.

  • x0 (np.ndarray, optional) – Initial values for the global stage. Defaults to the zero vector.

  • global_solver (str, optional) – Population-based solver for stage 1. Must be 'diffev' or 'diffev2' (default: 'diffev2').

  • local_solver (str, optional) – Local solver for stage 2. Must be 'fmin' or 'fmin_powell' (default: 'fmin_powell').

  • global_maxiter (int, optional) – Maximum iterations for the global stage. Defaults to 200.

  • global_maxfun (int, optional) – Maximum function evaluations for the global stage. Defaults to 10 * n * 20 where n is the number of energy bins.

  • local_maxiter (int, optional) – Maximum iterations for the local stage. Defaults to 2000.

  • local_maxfun (int, optional) – Maximum function evaluations for the local stage. Defaults to 20000.

  • npop (int, optional) – Population size for the global stage. Defaults to min(10 * n, 200) where n is the number of energy bins.

  • smoothness_order (int, optional) – Smoothness constraint order (0, 1, or 2), default: 0.

  • smoothness_weight (float, optional) – Weight for the smoothness term, default: 1.0.

Returns:

Unfolded spectrum (n,). Returns a zero vector if both stages fail.

Return type:

np.ndarray

bssunfold.core.unfold_genetic.solve_genetic(A: ndarray, b: ndarray, x0: ndarray | None = None, solver: str = 'pso', epoch: int = 500, pop_size: int = 50, regularization: float = 0.01, norm: int = 2, smoothness_order: int = 2, smoothness_weight: float = 1.0, entropy_weight: float = 0.0, n_runs: int = 1, early_stop: int | None = None, half_range: float = 2.0, two_step: bool = False, n_coarse: int | None = None, smoother: str = 'none', sigma_smooth: float = 2.0, crossover: str = 'single', mutation: str = 'random', pareto_select: str = 'knee', random_state: int | None = None, verbose: bool = False, extra_starting: ndarray | None = None) ndarray[source]#

Solve the unfolding problem using a meta-heuristic optimizer.

The optimizer searches in log space (y = log(x)) so that the wide dynamic range of neutron spectra is handled naturally. The population is seeded with a Landweber warm-start solution (or the provided x0) and bounded to log(seed) +/- half_range decades. All objective terms are scale-consistent (dimensionless), which prevents the optimizer from producing a noisy, arbitrary spectrum.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray, optional) – Initial spectrum guess. If None (or all zeros), a Landweber warm-start solution is used to seed the population.

  • solver (str, optional) – Meta-heuristic algorithm: ‘pso’, ‘ga’, ‘de’, ‘es’, ‘ep’, ‘abc’, ‘gwo’, ‘cmaes’ or ‘nsga2’ (default: ‘pso’).

  • epoch (int, optional) – Maximum number of generations/iterations (default: 500).

  • pop_size (int, optional) – Population size (default: 50).

  • regularization (float, optional) – Tikhonov regularisation weight alpha (default: 1e-2).

  • norm (int, optional) – Norm for the regularisation term (1 for L1, 2 for L2), default: 2.

  • smoothness_order (int, optional) – Second-difference smoothing order (0, 1 or 2), default: 2.

  • smoothness_weight (float, optional) – Weight of the smoothing term (default: 1.0).

  • entropy_weight (float, optional) – Weight of the negative Shannon-entropy objective (0 disables it).

  • n_runs (int, optional) – Number of independent optimisation runs; results are averaged (default: 1). Not used by the ‘nsga2’ solver.

  • early_stop (int, optional) – Stop if the global best does not improve for this many consecutive epochs (MEALPY early stopping). Not used by the numpy engines.

  • half_range (float, optional) – Half-width of the log-space search bounds in decades around the seed (default: 2.0).

  • two_step (bool, optional) – If True, run the two-step genetic scheme (TGASU-style): the problem is first solved on a coarse energy grid and the result is interpolated back to seed the full-resolution population (default: False).

  • n_coarse (int, optional) – Number of coarse bins for the two_step mode. When None, it is chosen as max(8, n // 4).

  • smoother (str, optional) – Post-processing smoother: ‘none’, ‘gaussian’, ‘mbc’, ‘gaussian_mbc’ or ‘second_difference’ (default: ‘none’).

  • sigma_smooth (float, optional) – Gaussian filter sigma for the smoothers (default: 2.0).

  • crossover (str, optional) – GA crossover operator: ‘single’ (single-point) or ‘arithmetic’ (beta-weighted, TGASU). Only used by the numpy GA engine (default: ‘single’).

  • mutation (str, optional) – GA mutation operator: ‘random’ or ‘iterative’ (generation-decreasing step, TGASU). Only used by the numpy GA engine (default: ‘random’).

  • pareto_select (str, optional) – Selection from the Pareto front for the ‘nsga2’ solver: ‘knee’, ‘min_residual’ or ‘max_entropy’ (default: ‘knee’).

  • random_state (int, optional) – Random seed for reproducibility.

  • verbose (bool, optional) – If True, MEALPY logs the optimisation progress to the console.

  • extra_starting (np.ndarray, optional) – Additional starting individual (in linear spectrum units) injected into the initial population without shifting the search box. Used internally by the two-step scheme.

Returns:

Unfolded spectrum (n,). Returns a zero vector if solving failed.

Return type:

np.ndarray

bssunfold.core.unfold_smt.solve_smt(A: ndarray, b: ndarray, x0: ndarray | None = None, nonneg: bool = True, timeout_ms: int = 10000, random_state: int | None = None, objective: str = 'l2') ndarray[source]#

Solve the unfolding problem with an SMT solver.

Minimizes the L2 residual ||A x - b||_2 and then the total fluence sum(x) over the non-negative orthant using the Z3 optimizer (via the exact KKT characterization of the non-negative least-squares optimum). If the L2 solve does not converge within its (bounded) time budget, e.g. on large systems, the solver falls back to the L1 residual ||A x - b||_1.

The system A x = b is usually underdetermined (fewer detectors than energy bins), so the lexicographic objective selects a deterministic solution.

Parameters:
  • A (np.ndarray) – Response matrix of size (m, n).

  • b (np.ndarray) – Measurement vector of size (m,).

  • x0 (np.ndarray, optional) – Not used (provided for API compatibility). Z3 has no warm start.

  • nonneg (bool, optional) – Constrain the solution to x >= 0 (default: True).

  • timeout_ms (int, optional) – SMT solver timeout in milliseconds (default: 10000).

  • random_state (int, optional) – Random seed for the SMT solver, for reproducibility.

  • objective (str, optional) – Residual objective: 'l2' (default, least squares) or 'l1'. On a non-converging L2 solve the L1 objective is used as a fallback.

Returns:

Unfolded spectrum (n,). Returns a zero vector if solving failed.

Return type:

np.ndarray

bssunfold.core.unfold_scip.solve_scip(A: ndarray, b: ndarray, x0: ndarray | None = None, alpha: float = 0.0001, norm: int = 2, timeout: float = 10.0, smoothness_order: int = 0, smoothness_weight: float = 1.0, nonneg: bool = True, random_state: int | None = None, ub: ndarray | None = None) ndarray | None[source]#

Solve the unfolding problem with the SCIP optimizer.

Minimizes 0.5 * ||A x - b||^2 + penalty(x) with penalty given by alpha * ||x||^2 (L2), alpha * sum(x) (L1, exact under x >= 0) or a derivative smoothness term, subject to x >= 0 when nonneg.

Parameters:
  • A (np.ndarray) – Response matrix of size (m, n).

  • b (np.ndarray) – Measurement vector of size (m,).

  • x0 (np.ndarray, optional) – Initial values, used as a warm start for the solver.

  • alpha (float, optional) – Regularization parameter, default: 1e-4.

  • norm (int, optional) – Norm type (1 for L1, 2 for L2), default: 2.

  • timeout (float, optional) – Time limit in seconds, default: 10.0.

  • smoothness_order (int, optional) – Smoothness constraint order (0, 1, or 2), default: 0.

  • smoothness_weight (float, optional) – Weight for the smoothness term, default: 1.0.

  • nonneg (bool, optional) – Constrain the solution to x >= 0, default: True.

  • random_state (int, optional) – Random seed for the solver, for reproducibility.

Returns:

Unfolded spectrum (n,), or None if solving failed.

Return type:

Optional[np.ndarray]

bssunfold.core.unfold_docplex.solve_docplex(A: ndarray, b: ndarray, x0: ndarray | None = None, alpha: float = 0.0001, norm: int = 2, timeout: float = 10.0, smoothness_order: int = 0, smoothness_weight: float = 1.0, nonneg: bool = True, random_state: int | None = None, ub: ndarray | None = None) ndarray | None[source]#

Solve the unfolding problem with CPLEX (docplex).

Minimizes 0.5 * ||A x - b||^2 + penalty(x) with penalty given by alpha * ||x||^2 (L2), alpha * sum(x) (L1, exact under x >= 0) or a derivative smoothness term, subject to x >= 0 when nonneg.

Parameters:
  • A (np.ndarray) – Response matrix of size (m, n).

  • b (np.ndarray) – Measurement vector of size (m,).

  • x0 (np.ndarray, optional) – Initial values (accepted for API compatibility; CPLEX QP has no warm start for continuous models).

  • alpha (float, optional) – Regularization parameter, default: 1e-4.

  • norm (int, optional) – Norm type (1 for L1, 2 for L2), default: 2.

  • timeout (float, optional) – Time limit in seconds, default: 10.0.

  • smoothness_order (int, optional) – Smoothness constraint order (0, 1, or 2), default: 0.

  • smoothness_weight (float, optional) – Weight for the smoothness term, default: 1.0.

  • nonneg (bool, optional) – Constrain the solution to x >= 0, default: True.

  • random_state (int, optional) – Random seed for the solver, for reproducibility.

Returns:

Unfolded spectrum (n,), or None if solving failed.

Return type:

Optional[np.ndarray]

bssunfold.core.unfold_epic.solve_epic(A: ndarray, b: ndarray, x0: ndarray | None = None, target_sigmas: ndarray | None = None, sigma_frac: float = 0.1, regularization_order: int = 1, non_neg: bool = True, noise_var: float | None = None, homogeneous_step: bool = True, regularize: dict[str, Any] | None = None, beta_shift_k: float = 0, beta_distance: float = 2, EPIC_bool: ndarray | None = None, V: ndarray | None = None, LSQpar: dict[str, Any] | None = None) ndarray[source]#

Solve the unfolding problem with EPIC Tikhonov regularization.

Selects the prior variances of the regularization operator H such that the a posteriori variances of the model parameters equal the squared target sigmas, then solves the weighted least squares problem.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray, optional) – Not used (provided for API compatibility).

  • target_sigmas (np.ndarray, optional) – Target a posteriori standard deviations of the model parameters. If None, derived as sigma_frac times the magnitude of the naive least-squares solution. Must be strictly positive.

  • sigma_frac (float, optional) – Fraction used to derive the default target sigmas (default: 0.1).

  • regularization_order (int, optional) – Regularization operator order: 0 (identity), 1 (first derivative, default) or 2 (second derivative).

  • non_neg (bool, optional) – Apply non-negativity constraints to the model parameters (default: True).

  • noise_var (float, optional) – Variance of the i.i.d. misfit errors used to build Cx (default: None, meaning Cx is the identity matrix).

  • homogeneous_step (bool, optional) – Run a preliminary homogeneous Ch search (default: True).

  • regularize (dict, optional) – If given (can be empty), damp the EPIC weights towards a minimum-norm solution. May carry sigma_weight.

  • beta_shift_k (float, optional) – Center shift for the beta bounds (default: 0).

  • beta_distance (float, optional) – Distance kept from the representability limit (default: 2).

  • EPIC_bool (np.ndarray, optional) – Boolean mask of which parameters are subject to the EPIC.

  • V (np.ndarray, optional) – Matrix mapping the searched betas to the regularization rows, beta = V @ y (shape (H.shape[0], len(y))).

  • LSQpar (dict, optional) – Tuning parameters for the nonlinear least-squares solver.

Returns:

Unfolded spectrum (n,).

Return type:

np.ndarray

bssunfold.core.unfold_interpret.solve_interpret(A: ndarray, b: ndarray, alpha: float, norm: int = 2, smoothness_order: int = 0, smoothness_weight: float = 1.0, enforce_norm: bool = False, norm_value: float = 1.0, x0: ndarray | None = None, tolerance: float = 1e-08, variable_names: Sequence[str] | None = None, ridge_coeff: Any = 'auto') ndarray[source]#

Solve the unfolding QP through pyoptexplain and return the spectrum.

Parameters:
  • A (np.ndarray) – Response matrix (m, n).

  • b (np.ndarray) – Measurement vector (m,).

  • alpha (float) – Regularization parameter.

  • norm (int, optional) – Penalty norm, 1 or 2 (default: 2).

  • smoothness_order (int, optional) – Smoothness derivative order, 0, 1 or 2 (default: 0).

  • smoothness_weight (float, optional) – Weight of the smoothness term (default: 1.0).

  • enforce_norm (bool, optional) – Add sum(x) == norm_value (default: False).

  • norm_value (float, optional) – Target total fluence for the norm equality (default: 1.0).

  • x0 (np.ndarray, optional) – Warm start, accepted for API compatibility (unused).

  • tolerance (float, optional) – Solver feasibility/optimality tolerance (default: 1e-8).

  • variable_names (sequence of str, optional) – Energy-group variable names.

  • ridge_coeff (float or "auto", optional) – Diagonal ridge for norm == 1 (default: "auto").

Returns:

Unfolded spectrum (n,).

Return type:

np.ndarray

Raises:

RuntimeError – If the solver does not return a primal solution.

bssunfold.core.unfold_interpret.interpret_qp(A: ndarray, b: ndarray, alpha: float, *, norm: int = 2, smoothness_order: int = 0, smoothness_weight: float = 1.0, enforce_norm: bool = False, norm_value: float = 1.0, E_MeV: ndarray | None = None, detector_names: Sequence[str] | None = None, tolerance: float = 1e-08, ridge_coeff: Any = 'auto', relative_deltas: Sequence[float] = (-0.05, -0.01, 0.01, 0.05), relaxation_deltas: Sequence[float] = (0.0, 0.05, 0.1), nonneg_deltas: Sequence[float] = (0.0, 0.01, 0.05), sensitivity_deltas: Sequence[float] = (0.01, 0.05), regularization_sweep: Sequence[float] | None = None, run_robustness: bool = True, run_scenarios: bool = True, run_detector_sensitivity: bool = True, run_regularization_sweep: bool = True, run_nonnegativity_relaxation: bool = True) InterpretationResult[source]#

Solve and interpret the unfolding QP with pyoptexplain.

Parameters:
  • A (np.ndarray) – Response matrix (m, n).

  • b (np.ndarray) – Measurement vector (m,).

  • alpha (float) – Regularization parameter.

  • norm (int, optional) – Penalty norm, 1 or 2 (default: 2).

  • smoothness_order (int, optional) – Smoothness derivative order, 0, 1 or 2 (default: 0).

  • smoothness_weight (float, optional) – Weight of the smoothness term (default: 1.0).

  • enforce_norm (bool, optional) – Add sum(x) == norm_value (default: False).

  • norm_value (float, optional) – Target total fluence for the norm equality (default: 1.0).

  • E_MeV (np.ndarray, optional) – Energy grid for the report tables.

  • detector_names (sequence of str, optional) – Names of the detector rows of A/b.

  • tolerance (float, optional) – Solver feasibility/optimality tolerance (default: 1e-8).

  • ridge_coeff (float or "auto", optional) – Diagonal ridge added to Q when norm == 1 and smoothness_order == 0 to cure rank deficiency of A'A. "auto" (default) uses 1e-8 * trace(Q) / n. Set to 0.0 to disable the ridge.

  • relative_deltas (sequence of float, optional) – Relative perturbations for the robustness analysis (default: -5..5%).

  • relaxation_deltas (sequence of float, optional) – RHS deltas for the norm relaxation curve (default: 0, 0.05, 0.1).

  • nonneg_deltas (sequence of float, optional) – Allowed-negative magnitudes to probe (default: 0, 0.01, 0.05).

  • sensitivity_deltas (sequence of float, optional) – Per-detector relative perturbations (default: 1%, 5%).

  • regularization_sweep (sequence of float, optional) – Explicit alpha grid; default derives a grid around alpha.

  • run_robustness (bool, optional) – Run the perturbation robustness analysis (default: True).

  • run_scenarios (bool, optional) – Run the pyoptexplain structured scenarios (default: True).

  • run_detector_sensitivity (bool, optional) – Run the per-detector sensitivity analysis (default: True).

  • run_regularization_sweep (bool, optional) – Run the regularization sweep (default: True).

  • run_nonnegativity_relaxation (bool, optional) – Run the non-negativity relaxation analysis (default: True).

Returns:

The interpreted solution (spectrum, report, metrics, tables).

Return type:

InterpretationResult

bssunfold.core.unfold_interpret.build_interpretation_qp(A: ndarray, b: ndarray, alpha: float, norm: int = 2, smoothness_order: int = 0, smoothness_weight: float = 1.0, enforce_norm: bool = False, norm_value: float = 1.0, lower_bound: float = 0.0, variable_names: Sequence[str] | None = None, equality_name: str = 'norm', ridge_coeff: Any = 'auto') Any[source]#

Build the pyoptexplain QP handle for the unfolding problem.

The quadratic program matches the model solved by solve_qpsolvers (objective convention 0.5 * x'Qx + c'x):

  • norm == 2: Q = A'A + alpha*sw*L'L (smoothness_order 1/2) or Q = A'A + alpha*I, c = -A'b.

  • norm == 1: Q = A'A + alpha*sw*L'L, c = -A'b + alpha*1 (the L1 penalty is linear and exact under x >= 0).

The spectrum is constrained to x >= lower_bound. When enforce_norm=True the equality sum(x) == norm_value is added as a named block (default "norm").

Parameters:
  • A (np.ndarray) – Response matrix (m, n).

  • b (np.ndarray) – Measurement vector (m,).

  • alpha (float) – Regularization parameter (>= 0).

  • norm (int, optional) – Penalty norm, 1 or 2 (default: 2).

  • smoothness_order (int, optional) – Smoothness derivative order, 0, 1 or 2 (default: 0).

  • smoothness_weight (float, optional) – Weight of the smoothness term (default: 1.0).

  • enforce_norm (bool, optional) – Add sum(x) == norm_value (default: False).

  • norm_value (float, optional) – Target total fluence for the norm equality (default: 1.0).

  • lower_bound (float, optional) – Shared lower bound on every energy group (default: 0.0).

  • variable_names (sequence of str, optional) – Names of the energy-group variables (default: E0..E{n-1}).

  • equality_name (str, optional) – Name of the norm equality block (default: "norm").

  • ridge_coeff (float or "auto", optional) – Diagonal ridge added to Q when norm == 1 and smoothness_order == 0 to cure rank deficiency of A'A. "auto" (default) uses 1e-8 * trace(Q) / n. Set to 0.0 to disable the ridge.

Returns:

A pyoptexplain problem handle; call handle.quadratic_representation() for the analysis surface.

Return type:

QuadraticMatrixProblemHandle

Raises:
  • ImportError – If pyoptexplain is not installed.

  • ValueError – If the arguments are invalid or Q is not positive semidefinite.

bssunfold.core.unfold_cs.solve_cs(A: ndarray, b: ndarray, x0: ndarray | None = None, n_atoms: int | None = None, sparsity: int | None = None, dictionary: ndarray | None = None, n_dictionary_iterations: int = 20, sigma_min: float = 0.01, sigma_decrease_factor: float = 0.5, mu_0: float = 1.0, L: int = 3, max_iterations: int = 1000, tolerance: float = 1e-06, random_state: int | None = None) tuple[ndarray, int, bool][source]#

Solve the unfolding problem using Compressive Sensing (CS).

The spectrum x is represented sparsely in a learned dictionary D as x = D @ alpha. The measurement equation b = A @ x becomes b = (A @ D) @ alpha, which is solved for the sparse alpha using SL0. Finally the spectrum is reconstructed as x = D @ alpha.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray, optional) – Initial guess (n,). Used to seed the dictionary training signals.

  • n_atoms (int, optional) – Number of dictionary atoms. Defaults to max(n, 2 * m).

  • sparsity (int, optional) – Target sparsity for dictionary learning. Defaults to max(1, n // 20).

  • dictionary (np.ndarray, optional) – Pre-learned dictionary (n x n_atoms). If provided, dictionary learning is skipped.

  • n_dictionary_iterations (int, optional) – Number of K-SVD iterations (default: 20).

  • sigma_min (float, optional) – SL0 minimum sigma (default: 0.01).

  • sigma_decrease_factor (float, optional) – SL0 sigma decrease factor (default: 0.5).

  • mu_0 (float, optional) – SL0 step-size factor (default: 1.0).

  • L (int, optional) – SL0 inner iterations per sigma (default: 3).

  • max_iterations (int, optional) – SL0 maximum outer iterations (default: 1000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Tuple of (solution, iterations, converged).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_cs.solve_omp(D: ndarray, y: ndarray, sparsity: int, tolerance: float = 1e-06) ndarray[source]#

Solve sparse coding problem using Orthogonal Matching Pursuit (OMP).

Finds a sparse coefficient vector alpha such that y ~= D @ alpha with at most sparsity non-zero entries.

Parameters:
  • D (np.ndarray) – Dictionary matrix (n x k).

  • y (np.ndarray) – Signal to be represented (n,).

  • sparsity (int) – Maximum number of non-zero coefficients.

  • tolerance (float, optional) – Residual tolerance for early stopping (default: 1e-6).

Returns:

Sparse coefficient vector (k,).

Return type:

np.ndarray

bssunfold.core.unfold_cs.solve_ksvd(signals: ndarray, n_atoms: int, n_iterations: int = 20, sparsity: int = 5, random_state: int | None = None) ndarray[source]#

Learn a dictionary using the K-SVD algorithm.

Parameters:
  • signals (np.ndarray) – Training signals (n x m), one column per training sample.

  • n_atoms (int) – Number of dictionary atoms.

  • n_iterations (int, optional) – Number of K-SVD iterations (default: 20).

  • sparsity (int, optional) – Target sparsity for sparse coding (default: 5).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Learned dictionary (n x n_atoms).

Return type:

np.ndarray

bssunfold.core.unfold_cs.solve_sl0(A: ndarray, b: ndarray, sigma_min: float = 0.01, sigma_decrease_factor: float = 0.5, mu_0: float = 1.0, L: int = 3, max_iterations: int = 1000, tolerance: float = 1e-06) ndarray[source]#

Reconstruct a sparse signal using the Smoothed L0 (SL0) algorithm.

SL0 approximates the L0 norm by a smooth surrogate and performs a steepest-descent / projection iteration to find the sparsest solution of the underdetermined linear system b = A @ x.

Parameters:
  • A (np.ndarray) – Sensing matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • sigma_min (float, optional) – Minimum value of the smoothing parameter sigma (default: 0.01).

  • sigma_decrease_factor (float, optional) – Factor by which sigma is decreased each outer iteration (default: 0.5).

  • mu_0 (float, optional) – Step-size factor for the steepest descent (default: 1.0). The effective step is mu_0 * x * exp(-x^2 / (2 sigma^2)); mu_0 = 1 drives small coefficients toward zero without sign flips.

  • L (int, optional) – Number of inner steepest-descent iterations per sigma (default: 3).

  • max_iterations (int, optional) – Maximum number of outer iterations (default: 1000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

Returns:

Reconstructed sparse signal (n,).

Return type:

np.ndarray

bssunfold.core.unfold_doroshenko.solve_doroshenko(A: ndarray, b: ndarray, x0: ndarray, max_iterations: int = 1000, tolerance: float = 1e-06, regularization: float = 0.0) tuple[ndarray, int, bool][source]#

Solve unfolding problem using Doroshenko coordinate update method.

Uses incremental residual update for O(n) per-coordinate complexity instead of O(n^2) from full matrix-vector products.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial guess (n,).

  • max_iterations (int, optional) – Maximum iterations (default: 1000).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

  • regularization (float, optional) – Regularization strength to prevent division by zero (default: 0.0).

Returns:

Tuple of (solution, iterations, converged).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_directed_divergence.solve_directed_divergence(A: ndarray, b: ndarray, x0: ndarray, max_iterations: int = 200, tol_chi2: float = 1.0, tol_rel: float = 1e-06, relative_uncertainty: float = 0.05, sigma: ndarray | None = None, smoothness_order: int = 0, smoothness_weight: float = 0.0) tuple[ndarray, int, bool][source]#

Solve a non-negative unfolding problem by directed divergence.

A must be the response matrix used by Detector; its columns already include the energy-bin integration weights. Smoothing is the proximal Tikhonov step argmin ||x-y||^2 + alpha ||Lx||^2.

bssunfold.core.unfold_kaczmarz.solve_kaczmarz(A: ndarray, b: ndarray, x0: ndarray, max_iterations: int = 1000, omega: float = 1.0, tolerance: float = 1e-06) tuple[ndarray, int, bool][source]#

Solve unfolding problem using Kaczmarz algorithm (ART).

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial guess (n,).

  • max_iterations (int, optional) – Maximum iterations (default: 1000).

  • omega (float, optional) – Relaxation parameter (0 < omega <= 2), default: 1.0.

  • tolerance (float, optional) – Convergence tolerance (default: 1e-6).

Returns:

Tuple of (solution, iterations, converged).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_lmfit.solve_lmfit(A: ndarray, b: ndarray, x0: ndarray, method: str = 'lbfgsb', model_name: str = 'elastic', regularization: float = 0.0001, regularization2: float = 0.0001, l1_weight: float = 0.5) tuple[ndarray, bool, str, int][source]#

Solve unfolding problem using lmfit with L1/L2/Elastic regularization.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial guess (n,).

  • method (str, optional) – lmfit solver name (leastsq, lbfgsb, etc.), default: “lbfgsb”.

  • model_name (str, optional) – Regularization model: elastic, lasso, ridge, default: “elastic”.

  • regularization (float, optional) – L1 regularization strength, default: 1e-4.

  • regularization2 (float, optional) – L2 regularization strength for elastic net, default: 1e-4.

  • l1_weight (float, optional) – L1 weight for elastic net (0=pure L2, 1=pure L1), default: 0.5.

Returns:

Tuple of (solution, success, message, nfev).

Return type:

Tuple[np.ndarray, bool, str, int]

bssunfold.core.unfold_lmfit.select_regularization_aic_bic(A: ndarray, b: ndarray, x0: ndarray, method: str = 'lbfgsb', model_name: str = 'elastic', regularization: float = 0.0001, regularization2: float = 0.0001, l1_weight: float = 0.5, criterion: str = 'aic', lambda_range: tuple[float, float] = (1e-06, 0.1), n_lambda: int = 30, verbose: bool = True) dict[str, Any][source]#

Select the lmfit regularization parameter by an information criterion.

Sweeps n_lambda log-spaced regularization candidates, solves the lmfit problem for each, scores it with AIC/AICc/BIC (effective degrees of freedom and Gaussian likelihood of the data residual), and returns the candidate minimizing the chosen criterion.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial spectrum used for every candidate solve.

  • method (str, optional) – lmfit solver name, default: “lbfgsb”.

  • model_name (str, optional) – Regularization model: elastic, lasso, ridge, default: “elastic”.

  • regularization (float, optional) – Manual L1 regularization strength, used as fallback if every candidate solve fails, default: 1e-4.

  • regularization2 (float, optional) – L2 regularization strength for elastic net, default: 1e-4.

  • l1_weight (float, optional) – L1 weight for elastic net, default: 0.5.

  • criterion (str, optional) – Information criterion to minimize: ‘aic’, ‘aicc’ or ‘bic’, default: ‘aic’.

  • lambda_range (Tuple[float, float], optional) – Log-spaced range of lambda candidates, default: (1e-6, 1e-1).

  • n_lambda (int, optional) – Number of lambda candidates, default: 30.

  • verbose (bool, optional) – Print the selection summary, default: True.

Returns:

Keys: best_lambda, best_lambda2, best_criterion_value, best_index, best_df, lambda_candidates, aic_values, aicc_values, bic_values, df_values, criterion_used, model_name.

Return type:

Dict[str, Any]

Raises:

ValueError – If criterion is not one of ‘aic’, ‘aicc’, ‘bic’.

bssunfold.core.unfold_gravel.solve_gravel(A: ndarray, b: ndarray, x0: ndarray, tolerance: float = 1e-08, max_iterations: int = 1000, regularization: float = 0.0) tuple[ndarray, int, bool][source]#

Solve unfolding problem using the GRAVEL algorithm.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial spectrum guess (n,).

  • tolerance (float, optional) – Convergence tolerance (default: 1e-8).

  • max_iterations (int, optional) – Maximum iterations (default: 1000).

  • regularization (float, optional) – Regularization parameter (default: 0.0).

Returns:

Tuple of (solution, iterations, converged).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_maxed.solve_maxed(A: ndarray, b: ndarray, x0: ndarray, sigma_factor: float = 0.1, max_iterations: int = 5000, tolerance: float = 1e-06) tuple[ndarray, int, bool][source]#

Solve unfolding problem using MAXED (Maximum Entropy Deconvolution).

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Reference (prior) spectrum (n,).

  • sigma_factor (float, optional) – Relative measurement uncertainty (default: 0.1). Larger values → smoother spectrum (weaker data term).

  • max_iterations (int, optional) – Maximum L-BFGS-B iterations (default: 5000).

  • tolerance (float, optional) – Gradient convergence tolerance (default: 1e-6).

Returns:

(solution spectrum, iterations used, converged flag).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_tikhonov_legendre.solve_tikhonov_legendre(A: ndarray, b: ndarray, x0: ndarray | None = None, delta: float = 0.05, n_polynomials: int = 15) ndarray[source]#

Solve unfolding using Tikhonov regularization with Legendre basis.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray, optional) – Not used (provided for API compatibility).

  • delta (float, optional) – Regularization parameter (default: 0.05).

  • n_polynomials (int, optional) – Number of Legendre polynomials (default: 15).

Returns:

Unfolded spectrum (n,).

Return type:

np.ndarray

bssunfold.core.unfold_bayes.solve_bayes(A: ndarray, b: ndarray, x0: ndarray | None = None, max_iterations: int = 4000, tolerance: float = 0.001) ndarray[source]#

Solve unfolding problem using Bayesian iterative unfolding (D’Agostini).

Pure numpy implementation of the D’Agostini algorithm. The response matrix is column-normalised so each column sums to 1 (conditional probability P(D_j | E_i)), then the result is rescaled to physical units via division by the column sums.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray, optional) – Prior spectrum. If None, uniform prior is used.

  • max_iterations (int, optional) – Maximum iterations (default: 4000).

  • tolerance (float, optional) – Relative L2 convergence tolerance (default: 1e-3).

Returns:

Unfolded spectrum (n,) in physical units.

Return type:

np.ndarray

bssunfold.core.unfold_bayes_spline_regularization.solve_bayes_spline(A: ndarray, b: ndarray, x0: ndarray | None = None, max_iterations: int = 4000, tolerance: float = 0.001, spline_degree: int = 3, spline_smooth: float = 0.01) ndarray[source]#

Solve unfolding problem using Bayes with spline regularization.

Implements the D’Agostini iterative Bayesian unfolding from scratch. The response matrix is column-normalised (each column sums to 1) so the algorithm works in effective-count space, but the UnivariateSpline smoother is applied to the physical spectrum to avoid boundary artifacts that appear when rescaling low-sensitivity bins back to physical units.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray, optional) – Prior spectrum.

  • max_iterations (int, optional) – Maximum iterations (default: 4000).

  • tolerance (float, optional) – Relative L2 convergence tolerance (default: 1e-3).

  • spline_degree (int, optional) – Spline degree (default: 3).

  • spline_smooth (float, optional) – Spline smoothing parameter (default: 1e-2).

Returns:

Unfolded spectrum (n,).

Return type:

np.ndarray

bssunfold.core.unfold_statreg.solve_statreg(A: ndarray, b: ndarray, x0: ndarray | None = None, E_MeV: ndarray | None = None, unfoldermethod: str = 'EmpiricalBayes', regularization: float | None = None, basis_name: str = 'CubicSplines', boundary: str | None = None, derivative_degree: int = 2) ndarray[source]#

Solve unfolding problem using Turchin’s statistical regularisation.

Parameters:
  • A (np.ndarray) – Response matrix (m × n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray, optional) – Not used (provided for API compatibility).

  • E_MeV (np.ndarray, optional) – Energy grid (n,). Used for log-energy penalty scaling.

  • unfoldermethod (str, optional) – Regularisation method: 'EmpiricalBayes' (L-curve, default) or 'User' (fixed α).

  • regularization (float, optional) – Regularisation parameter α for 'User' method (default: 1e-4).

  • basis_name (str, optional) – Ignored (kept for API compatibility).

  • boundary (str, optional) – Ignored (kept for API compatibility).

  • derivative_degree (int, optional) – Derivative order for penalty. Only 2 is implemented.

Returns:

Unfolded spectrum (n,).

Return type:

np.ndarray

bssunfold.core.unfold_reconst.solve_reconst(A: ndarray, b: ndarray, x0: ndarray | None = None, E_MeV: ndarray | None = None, pp: float = 0.001, alpha: float = -1.0, beta: float = 0.0, sigma_b: ndarray | None = None) ndarray[source]#

Solve unfolding problem using Turchin’s statistical regularization.

Pure numpy implementation of the RECONST.FOR algorithm (STREG1). Solves (B * beta + Omega * alpha) * f = A_vec * beta.

Parameters:
  • A (np.ndarray) – Response matrix (M, N).

  • b (np.ndarray) – Measurement vector (M,).

  • x0 (np.ndarray, optional) – Ignored (API compatibility).

  • E_MeV (np.ndarray, optional) – Ignored (API compatibility).

  • pp (float, optional) – PP parameter (default: 1e-3).

  • alpha (float, optional) – Regularization. >0 fixed, <0 auto (default: -1).

  • beta (float, optional) – Data fidelity. >0 fixed, <=0 auto (default: 0).

  • sigma_b (np.ndarray, optional) – Measurement uncertainties (M,). If None, sqrt(b) used.

Returns:

Unfolded spectrum (N,).

Return type:

np.ndarray

bssunfold.core.unfold_scipy_direct_method.solve_scipy_direct(A: ndarray, b: ndarray, x0: ndarray | None = None, tolerance: float = 1e-08, max_iterations: int = 4000, method: str = 'cg') ndarray[source]#

Solve unfolding problem using scipy sparse linear solvers.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray, optional) – Not used (provided for API compatibility).

  • tolerance (float, optional) – Solver tolerance (default: 1e-8).

  • max_iterations (int, optional) – Maximum solver iterations (default: 4000).

  • method (str, optional) – Solver method. One of: ‘cg’, ‘cgs’, ‘bicgstab’, ‘gmres’, ‘lgmres’, ‘minres’, ‘gcrotmk’, ‘qmr’, ‘tfqmr’, ‘lsqr’, ‘lsmr’ (default: ‘cg’).

Returns:

Unfolded spectrum (n,).

Return type:

np.ndarray

bssunfold.core.unfold_tsvd.solve_tsvd(A: ndarray, b: ndarray, x0: ndarray | None = None, method: str = 'discrepancy', k: int | None = None, threshold: float | None = None, noise_level: float | None = None, svd_solver: str = 'full') ndarray[source]#

Solve unfolding problem using Truncated SVD (TSVD).

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray, optional) – Not used (provided for API compatibility).

  • method (str, optional) – K-selection method: ‘discrepancy’, ‘l_curve’, ‘gcv’, ‘energy’, ‘threshold_ratio’, ‘median_threshold’, ‘donoho’ (default: ‘discrepancy’).

  • k (int, optional) – Fixed number of singular values to keep. Overrides method.

  • threshold (float, optional) – Threshold ratio for singular value truncation.

  • noise_level (float, optional) – Noise level estimate for discrepancy principle.

  • svd_solver (str, optional) – SVD backend: 'full' (dense LAPACK, default), 'arpack' or 'propack'. The iterative backends are only used when k is fixed; automatic k-selection falls back to the dense solver.

Returns:

Unfolded spectrum (n,).

Return type:

np.ndarray

bssunfold.core.unfold_lanczos.solve_lanczos(A: ndarray, b: ndarray, x0: ndarray | None = None, max_iterations: int | None = None, regularization: float = 1e-08, noise_level: float | None = None) tuple[ndarray, int, bool][source]#

Solve the unfolding problem with a Lanczos-hybrid method.

Performs Golub-Kahan bidiagonalization of A, generating a sequence of Krylov subspaces. On the projected problem min ||B_k y - bhat||^2 a Tikhonov term lambda * ||y||^2 is added, where lambda is selected automatically by GCV at each iteration. The iterate x_k = V_k y_k is an approximation in the Krylov subspace, so no a-priori spectrum is required (x0 is accepted for API compatibility only).

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray, optional) – Initial spectrum (unused, kept for API compatibility).

  • max_iterations (int, optional) – Maximum Krylov dimension. Defaults to min(A.shape).

  • regularization (float, optional) – Fallback regularization parameter used if GCV returns a degenerate value; default: 1e-8.

  • noise_level (float, optional) – Relative noise level. If given, iterations stop early by the discrepancy principle ||A x - b|| <= noise_level * sqrt(m).

Returns:

(spectrum, iterations, converged) where converged reports whether the discrepancy-principle criterion was met (or the Krylov space was fully spanned).

Return type:

tuple

bssunfold.core.unfold_cgls.solve_cgls(A: ndarray, b: ndarray, x0: ndarray | None = None, max_iterations: int = 100, tolerance: float = 1e-12, noise_level: float | None = None, regularization: float = 0.0, smoothness_order: int = 0) tuple[ndarray, int, bool][source]#

Solve the unfolding problem with the CGLS method.

Applies the conjugate gradient algorithm implicitly to the normal equations A^T A x = A^T b. A regularized solution is obtained by stopping the iterations once the normal-equation residual is sufficiently small, or (if noise_level is provided) once the discrepancy principle ||A x - b|| <= eta * noise_level * ||b|| is satisfied. If regularization is positive, the Tikhonov regularized system (A^T A + regularization^2 L^T L) x = A^T b is solved instead.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray, optional) – Initial guess (default: zero vector).

  • max_iterations (int, optional) – Maximum number of CGLS iterations (default: 100).

  • tolerance (float, optional) – Relative tolerance on the normal-equation residual norm (default: 1e-12).

  • noise_level (float, optional) – Relative noise level used for discrepancy-principle stopping (default: None).

  • regularization (float, optional) – Tikhonov regularization parameter. 0.0 disables the Tikhonov term and uses iterative regularization (default: 0.0).

  • smoothness_order (int, optional) – Derivative order of the regularization operator L used when regularization is positive: 0 (identity), 1 or 2 (default: 0).

Returns:

(spectrum, iterations, converged) where converged reports whether a stopping criterion was satisfied before reaching the maximum number of iterations.

Return type:

tuple

bssunfold.core.unfold_gks.solve_gks(A: ndarray, b: ndarray, x0: ndarray | None = None, smoothness_order: int = 0, regularization_method: str = 'gcv', max_iterations: int | None = None, regularization: float = 1e-08, noise_level: float | None = None) tuple[ndarray, int, bool][source]#

Solve the unfolding problem with the Generalized Krylov Subspace method.

Performs Golub-Kahan bidiagonalization of A and projects both A and the regularization operator L (identity or a derivative matrix) onto the Krylov subspace. At each iteration the projected Tikhonov problem min ||R_A y - bhat||^2 + lambda * ||R_L y||^2 is solved, where lambda is selected automatically by GCV, the Discrepancy Principle or the L-curve.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray, optional) – Initial spectrum (unused, kept for API compatibility).

  • smoothness_order (int, optional) – Derivative order of the regularization operator L: 0 (identity), 1 or 2 (default: 0).

  • regularization_method (str, optional) – Method for selecting the regularization parameter: 'gcv', 'dp', 'lcurve' or 'manual' (default: ‘gcv’).

  • max_iterations (int, optional) – Maximum Krylov dimension. Defaults to min(A.shape).

  • regularization (float, optional) – Manual/fallback regularization parameter (default: 1e-8).

  • noise_level (float, optional) – Relative noise level used by the Discrepancy Principle.

Returns:

(spectrum, iterations, converged) where converged reports whether the Krylov space was fully spanned or a fixed point of the projected solution was reached.

Return type:

tuple

bssunfold.core.unfold_tikhonov_tv.solve_tikhonov_tv(A: ndarray, b: ndarray, x0: ndarray | None = None, epsilon: float | None = None, mu: tuple[float, float, float] = (1.0, 1.0, 1.0), max_iterations: int = 100, type_: str = 'TT', beta: float = 1.0, zthr: float = 2.5, tolerance: float = 0.0001) tuple[ndarray, int, bool][source]#

Solve the noise-constrained Tikhonov-TV unfolding problem.

Solves min f(m) subject to ||A m - b||^2 = epsilon with the ADMM scheme of Gazzola & Gholami adapted to 1D spectra.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray, optional) – Initial spectrum guess (accepted for API compatibility; the iteration always starts from a zero vector like the original).

  • epsilon (float, optional) – (Estimate of) the squared 2-norm of the noise. If None, derived from the residuals of an unregularized least-squares solve.

  • mu (tuple, optional) – Penalty parameters for the Lagrangian terms, (mu1, mu2, mu3) (default: (1.0, 1.0, 1.0)).

  • max_iterations (int, optional) – Maximum number of ADMM iterations (default: 100).

  • type (str, optional) – Optimization problem to be solved: 'TT' (TV + Tikhonov), 'TV' (pure total variation) or 'T' (pure Tikhonov) (default: ‘TT’).

  • beta (float, optional) – Balancing parameter between the TV and Tikhonov terms. A scalar fixes its value; 'adapt' estimates it adaptively (only for type_='TT') (default: 1.0).

  • zthr (float, optional) – Threshold used by the adaptive beta estimation (default: 2.5).

  • tolerance (float, optional) – Stopping criterion based on the relative change of the solution (default: 1e-4).

Returns:

(spectrum, iterations, converged) where converged reports whether the stabilization stopping criterion was reached.

Return type:

tuple

bssunfold.core.unfold_sandii.solve_sandii(A: ndarray, b: ndarray, x0: ndarray, max_iterations: int = 50, tolerance: float = 0.001, chi_fac: int = 1, relative_uncertainty: float = 0.1, sigma: ndarray | None = None) tuple[ndarray, int, bool][source]#

Solve unfolding problem using the SAND-II algorithm.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial spectrum guess (n,).

  • max_iterations (int, optional) – Maximum number of iterations (default: 50).

  • tolerance (float, optional) – Maximum relative spectrum change used when chi_fac=0 (default: 1e-3).

  • chi_fac (int, optional) – Convergence criterion: 1 = stop when chi-square of the fit is not greater than the number of detectors; 0 = stop when the maximum relative change of the spectrum is below tolerance (default: 1).

  • relative_uncertainty (float, optional) – Relative measurement uncertainty used to derive detector sigma values when sigma is not supplied (default: 0.1).

  • sigma (np.ndarray, optional) – Explicit per-detector measurement uncertainties (m,). When given, overrides relative_uncertainty.

Returns:

(solution spectrum, iterations used, converged flag).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_crystal_ball.solve_crystal_ball(A: ndarray, b: ndarray, x0: ndarray | None = None, regularization: float = 0.0) tuple[ndarray, int, bool][source]#

Solve unfolding problem using the CRYSTAL BALL algorithm.

The spectrum is approximated as a linear combination of the detector response functions (rows of A). The coefficient vector alpha is obtained from the (regularized) normal equations (A A^T + lambda I) alpha = b and the spectrum reconstructed as phi = A^T alpha.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray, optional) – Unused by the direct CRYSTAL BALL method; accepted for a uniform solver signature.

  • regularization (float, optional) – Tikhonov regularization strength lambda added to the diagonal of A A^T to stabilise the inversion of the (usually ill-conditioned) Gram matrix (default: 0.0).

Returns:

(solution spectrum, 1, True). CRYSTAL BALL is a single-step method, so iterations is 1 and converged is always True.

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_rfsp_jul.solve_rfsp_jul(A: ndarray, b: ndarray, x0: ndarray, max_iterations: int = 200, tolerance: float = 0.0001, weights: ndarray | None = None) tuple[ndarray, int, bool][source]#

Solve unfolding problem using the RFSP-JUL algorithm.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial guess (n,). Also used as the reference iterate phi_prev at the first iteration.

  • max_iterations (int, optional) – Maximum number of iterations (default: 200).

  • tolerance (float, optional) – Convergence tolerance on the maximum relative spectrum change (default: 1e-4).

  • weights (np.ndarray, optional) – Per-detector weights W_i for the residual term. When None, all detectors are weighted equally (W_i = 1).

Returns:

(solution spectrum, iterations used, converged flag).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_staysl.solve_staysl(A: ndarray, b: ndarray, x0: ndarray, relative_uncertainty: float = 0.1, prior_uncertainty: float = 1.0, Cb: ndarray | None = None, Cx: ndarray | None = None, regularization: float = 1e-12) tuple[ndarray, int, bool][source]#

Solve unfolding problem using the STAY’SL Bayesian algorithm.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Prior spectrum guess (n,). Used as the Bayesian prior mean.

  • relative_uncertainty (float, optional) – Relative measurement uncertainty used to build the diagonal measurement covariance Cb = diag((rel * b)^2) when Cb is not supplied (default: 0.1).

  • prior_uncertainty (float, optional) – Relative prior uncertainty used to build the diagonal prior covariance Cx = diag((prior * x0)^2) when Cx is not supplied (default: 1.0, i.e. a broad prior).

  • Cb (np.ndarray, optional) – Explicit measurement covariance matrix (m x m). Overrides relative_uncertainty when given.

  • Cx (np.ndarray, optional) – Explicit prior covariance matrix (n x n). Overrides prior_uncertainty when given.

  • regularization (float, optional) – Small Tikhonov term added to the bracket (Cb + A Cx A^T) for numerical stability (default: 1e-12).

Returns:

(solution spectrum, 1, True). STAY’SL is a single-step method, so iterations is 1 and converged is always True.

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_express.solve_express(A: ndarray, b: ndarray, E: ndarray, x0: ndarray | None = None, n_groups: int = 6, interval_boundaries: ndarray | None = None, max_iterations: int = 3, tol_iteration: float = 0.05, relative_uncertainty: float = 0.05) tuple[ndarray, int, bool][source]#

Fit a piecewise-exponential spectrum directly to sphere readings.

bssunfold.core.unfold_bunki.solve_bunki(A: ndarray, b: ndarray, x0: ndarray, smoothing: float = 0.1, max_iterations: int = 1000, tolerance: float = 1e-06, lethargy_weights: ndarray | None = None) tuple[ndarray, int, bool][source]#

Solve unfolding problem using the BUNKI (SPUNIT) algorithm.

Parameters:
  • A (np.ndarray) – Lethargy-weighted response matrix (m x n) as built by the Detector class (see bssunfold.Detector()).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial spectrum guess (n,).

  • smoothing (float, optional) – Three-point smoothing factor (default: 0.1).

  • max_iterations (int, optional) – Maximum number of iterations (default: 1000).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

  • lethargy_weights (np.ndarray, optional) – Per-bin lethargy widths. Only needed when A is supplied as a per-bin (non-lethargy-weighted) response matrix; the Detector-built matrix is already lethargy-weighted so this can be left as None.

Returns:

(solution spectrum, iterations used, converged flag).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_bunkiut.solve_bunkiut(A: ndarray, b: ndarray, x0: ndarray, smoothing: float = 0.05, max_iterations: int = 1000, tolerance: float = 1e-06, lethargy_weights: ndarray | None = None) tuple[ndarray, int, bool][source]#

Solve unfolding problem using the BUNKI-UT (BON31G) algorithm.

Parameters:
  • A (np.ndarray) – Lethargy-weighted response matrix (m x n) as built by the Detector class (see bssunfold.Detector()).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial spectrum guess (n,).

  • smoothing (float, optional) – Three-point smoothing factor (default: 0.05).

  • max_iterations (int, optional) – Maximum number of iterations (default: 1000).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

  • lethargy_weights (np.ndarray, optional) – Per-bin lethargy widths. Only needed when A is supplied as a per-bin (non-lethargy-weighted) response matrix; the Detector-built matrix is already lethargy-weighted so this can be left as None.

Returns:

(solution spectrum, iterations used, converged flag).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_osem.solve_osem(A: ndarray, b: ndarray, x0: ndarray, max_iterations: int = 50, n_subsets: int = 1, tolerance: float = 1e-06) tuple[ndarray, int, bool][source]#

Solve unfolding problem using OSEM (ordered-subset EM).

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial spectrum guess (n,).

  • max_iterations (int, optional) – Maximum number of iterations (default: 50).

  • n_subsets (int, optional) – Number of ordered subsets over the detector readings (default: 1, i.e. standard MLEM).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

Returns:

(solution spectrum, iterations used, converged flag).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_osem_anlm.solve_osem_anlm(A: ndarray, b: ndarray, x0: ndarray, max_iterations: int = 50, n_subsets: int = 1, tolerance: float = 1e-06, h: float | None = None, search_window: int = 11, similarity_window: int = 3, alpha: float = 1.0, anlm_mode: str = 'subset', log_space: bool = True) tuple[ndarray, int, bool][source]#

Solve the unfolding problem with OSEM-ANLM.

OSEM update (article eq. 3 / pseudo-code step 4):

x^{n+1} = x^n * A_m^T ( b_m / (A_m x^n + eps) ) / ( A_m^T 1 + eps )

followed by the ANLM filter (pseudo-code step 5, f^{*(n+1,b)} = ANLMFilter(mu^{*(n+1,b)})) applied after every subset update when anlm_mode="subset" (default, per the article pseudo-code). With anlm_mode="post" the plain OSEM solution is produced first and the ANLM filter is applied once at the end (“OSEM reconstruction followed by ANLM regularization” in the article abstract). With n_subsets=1 the OSEM update reduces to standard MLEM.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial spectrum guess (n,).

  • max_iterations (int, optional) – Maximum number of full iterations (sweeps over all subsets) (default: 50).

  • n_subsets (int, optional) – Number of ordered subsets over the detector readings (default: 1, i.e. standard MLEM with per-iteration ANLM).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

  • h (float, optional) – Noise level for the ANLM filter. If None (default), it is estimated automatically from each intermediate spectrum.

  • search_window (int, optional) – ANLM search window N (default: 11, article optimum).

  • similarity_window (int, optional) – ANLM similarity (patch) window nu (default: 3, article optimum).

  • alpha (float, optional) – Spread of the Gaussian kernel over the similarity window (default: 1.0).

  • anlm_mode (str, optional) – 'subset' — ANLM after every subset update (default, article pseudo-code); 'post' — single ANLM application to the OSEM result.

  • log_space (bool, optional) – Apply the ANLM filter to the logarithm of the spectrum (default: True, scale-free for spectra spanning orders of magnitude). See anlm_filter_1d().

Returns:

(solution spectrum, iterations used, converged flag).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_osem_anlm.anlm_filter_1d(x: ndarray, h: float | None = None, search_window: int = 11, similarity_window: int = 3, alpha: float = 1.0, log_space: bool = True) ndarray[source]#

Two-stage asymptotic non-local means filter for 1D spectra.

Implements the ANLM regularisation of Jamaati et al. (2026) (eqs. 4-6 and the ANLM filter section) adapted to a one-dimensional energy grid:

  1. Patch (similarity-window) distances d(i, j) are computed with a Gaussian kernel of spread alpha over the similarity window nu; indices outside the signal are reflected at the borders.

  2. Stage 1 applies NLM with the uniform parameter h1 = 0.5 * sigma, producing a lightly denoised intermediate spectrum and the “initial” normalised weights w1(i, j).

  3. Stage 2 applies NLM with the point-wise parameter of article eq. 6, h2(i) = sqrt(sum_j w1(i, j)^2 * sigma^2) — the noise standard deviation smoothed by the initial weights — to the stage-1 output, incrementally reducing the noise while preserving structure.

By default (log_space=True) the filter operates on the logarithm of the spectrum: Bonner-sphere spectra span several orders of magnitude and the EM noise amplitude scales with the local fluence, so a single absolute filter parameter cannot match every bin. In log space the relative noise level is uniform across the grid, making the automatic h estimate scale-free (the filtered value becomes a weighted geometric mean, which also preserves non-negativity). Set log_space=False to filter in raw units exactly as the original CT formulation of the article.

Parameters:
  • x (np.ndarray) – Input spectrum (n,), typically non-negative.

  • h (float, optional) – Noise level sigma used by both stages (in log units when log_space=True). If None (default) the noise level is estimated automatically with estimate_noise_1d() (robust MAD on second differences).

  • search_window (int, optional) – Size N of the search window around each bin (article optimum: 11). Must be a positive integer; even values are rounded down to the preceding odd size.

  • similarity_window (int, optional) – Size nu of the Gaussian-weighted similarity (patch) window (article optimum: 3). Must be a positive integer; even values are rounded down to the preceding odd size.

  • alpha (float, optional) – Spread of the Gaussian kernel over the similarity window (default: 1.0). Must be positive.

  • log_space (bool, optional) – Filter the logarithm of the spectrum instead of the raw values (default: True, scale-free for spectra spanning orders of magnitude).

Returns:

Filtered spectrum (n,). Non-negative when log_space=True; reduces to the identity for search_window == 1.

Return type:

np.ndarray

bssunfold.core.unfold_louhi.solve_louhi(A: ndarray, b: ndarray, x0: ndarray | None = None, smoothness: float = 1.0, smooth_order: int = 1, max_iterations: int = 500, tolerance: float = 1e-06, relative_uncertainty: float = 0.1, sigma: ndarray | None = None, auto_smooth: bool = False, chi2_target: float | None = None) tuple[ndarray, int, bool][source]#

Solve the unfolding problem with the LOUHI78 algorithm.

Parameters:
  • A (np.ndarray) – Response matrix (m, n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray, optional) – Default (a-priori) spectrum (n,) used as the starting point and as the reference of the generalized smoothing term. When None, a flat unit spectrum is used.

  • smoothness (float, optional) – Smoothing weight lambda of the generalized smoothing term (default: 1.0). Ignored when auto_smooth is True.

  • smooth_order (int, optional) – Order of the smoothing operator: 0 (identity), 1 (first differences) or 2 (second differences); default 1.

  • max_iterations (int, optional) – Maximum number of Hildreth coordinate sweeps (default: 500).

  • tolerance (float, optional) – Maximum relative change between sweeps for convergence (default: 1e-6).

  • relative_uncertainty (float, optional) – Relative measurement uncertainty used to derive detector sigma values when sigma is not supplied (default: 0.1).

  • sigma (np.ndarray, optional) – Explicit per-detector measurement uncertainties (m,). When given, overrides relative_uncertainty.

  • auto_smooth (bool, optional) – Nonlinear regression mode of LOUHI78: adjust the smoothing weight by a golden-section search on log10(lambda) so that the data chi-square reaches chi2_target (default False).

  • chi2_target (float, optional) – Target data chi-square for auto_smooth. Defaults to the number of detectors (the expected value of the chi-square).

Returns:

(solution spectrum, sweeps used, converged flag).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_louhi.louhi_smoothing_matrix(n: int, smooth_order: int = 1) ndarray[source]#

Build the generalized smoothing operator L of LOUHI.

Parameters:
  • n (int) – Number of energy bins.

  • smooth_order (int, optional) – Order of the smoothing functional: 0 shrinks the solution toward the default spectrum (identity operator), 1 penalizes first differences of the deviation from the default spectrum and 2 penalizes second differences (default: 1).

Returns:

The (n, n) smoothing matrix L.

Return type:

np.ndarray

bssunfold.core.unfold_louhi.louhi_covariance(A: ndarray, sigma: ndarray, smoothness: float, smooth_order: int, x0: ndarray, x: ndarray) ndarray[source]#

Propagate measurement uncertainties for the LOUHI solution.

Follows the statistical error analysis of LOUHI78: the covariance of the free (strictly positive) spectrum bins is the inverse of the Hessian restricted to the active set, while constrained bins at zero carry no variance in the first-order propagation.

Parameters:
  • A (np.ndarray) – Response matrix (m, n).

  • sigma (np.ndarray) – Per-detector measurement uncertainties (m,).

  • smoothness (float) – Smoothing weight used for the solution.

  • smooth_order (int) – Order of the smoothing operator used for the solution.

  • x0 (np.ndarray) – Default spectrum used in the smoothing term.

  • x (np.ndarray) – LOUHI solution spectrum.

Returns:

Standard deviations of the spectrum bins (n,).

Return type:

np.ndarray

bssunfold.core.unfold_mapem.solve_mapem(A: ndarray, b: ndarray, x0: ndarray, prior: str = 'quadratic', beta: float = 0.001, prior_delta: float = 1.0, gamma: float = 1.0, max_iterations: int = 50, tolerance: float = 1e-06) tuple[ndarray, int, bool][source]#

Solve unfolding problem using penalised EM (OSMAPOSL, one-step-late).

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial spectrum guess (n,).

  • prior (str, optional) – Prior type: 'none', 'quadratic', 'logcosh' or 'relative_difference' (default: 'quadratic').

  • beta (float, optional) – Prior weight (default: 1e-3).

  • prior_delta (float, optional) – Width parameter of the quadratic/logcosh priors and additive floor of the relative-difference prior (default: 1.0).

  • gamma (float, optional) – Edge-preservation parameter of the relative-difference prior (default: 1.0).

  • max_iterations (int, optional) – Maximum number of iterations (default: 50).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

Returns:

(solution spectrum, iterations used, converged flag).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_bsrem.solve_bsrem(A: ndarray, b: ndarray, x0: ndarray, prior: str = 'none', beta: float = 0.001, prior_delta: float = 1.0, gamma: float = 1.0, max_iterations: int = 50, n_subsets: int = 1, tolerance: float = 1e-06, relaxation: float | Callable[[int], float] | None = None, addition_after_iteration: float = 0.0001) tuple[ndarray, int, bool][source]#

Solve unfolding problem using BSREM.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial spectrum guess (n,).

  • prior (str, optional) – Prior type: 'none', 'quadratic', 'logcosh' or 'relative_difference' (default: 'none').

  • beta (float, optional) – Prior weight (default: 1e-3).

  • prior_delta (float, optional) – Width parameter of the quadratic/logcosh priors and additive floor of the relative-difference prior (default: 1.0).

  • gamma (float, optional) – Edge-preservation parameter of the relative-difference prior (default: 1.0).

  • max_iterations (int, optional) – Maximum number of iterations (default: 50).

  • n_subsets (int, optional) – Number of ordered subsets over the detector readings (default: 1).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

  • relaxation (float or callable, optional) – Relaxation sequence alpha(n) as a constant or as a callable of the iteration number. If None, a constant 1 is used (default: None).

  • addition_after_iteration (float, optional) – Floor value the spectrum is clamped to after every sub-iteration to prevent bins being locked at zero (default: 1e-4).

Returns:

(solution spectrum, iterations used, converged flag).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_sart.solve_sart(A: ndarray, b: ndarray, x0: ndarray, max_iterations: int = 50, tolerance: float = 1e-06, relaxation: float | Callable[[int], float] | None = None) tuple[ndarray, int, bool][source]#

Solve unfolding problem using SART.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial spectrum guess (n,). The value of the first (lowest-energy) bin is held fixed during iteration because the detector response is (near-)zero there and cannot constrain it.

  • max_iterations (int, optional) – Maximum number of iterations (default: 50).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 1e-6).

  • relaxation (float or callable, optional) – Relaxation sequence alpha(n) as a constant or as a callable of the iteration number. If None, a constant 0.8 is used (default: None).

Returns:

(solution spectrum, iterations used, converged flag).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_ferdor.solve_ferdor(A: ndarray, b: ndarray, x0: ndarray, max_iterations: int = 100, tolerance: float = 0.001, smoothing: float = 0.001, chi_squared_target: float = 1.0, relative_uncertainty: float = 0.1, sigma: ndarray | None = None, min_alpha: float = 1e-12, max_alpha: float = 1000000000000.0) tuple[ndarray, int, bool][source]#

Solve unfolding problem using the FERDOR algorithm.

The smoothing weight alpha is adjusted iteratively (bisection) so that the reduced chi-square of the fit approaches chi_squared_target (discrepancy principle).

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial spectrum guess (n,). Accepted for interface compatibility; the constrained least-squares solution does not depend on it.

  • max_iterations (int, optional) – Maximum number of smoothing-weight adjustment iterations (default: 100).

  • tolerance (float, optional) – Relative tolerance on the reduced chi-square used to stop the bisection (default: 1e-3).

  • smoothing (float, optional) – Initial value of the smoothing weight alpha (default: 1e-3).

  • chi_squared_target (float, optional) – Target reduced chi-square per degree of freedom (default: 1.0).

  • relative_uncertainty (float, optional) – Relative measurement uncertainty used to derive the per-detector sigma values when sigma is not supplied (default: 0.1).

  • sigma (np.ndarray, optional) – Explicit per-detector measurement uncertainties (m,). When given, overrides relative_uncertainty.

  • min_alpha (float, optional) – Lower bound of the smoothing-weight search bracket (default: 1e-12).

  • max_alpha (float, optional) – Upper bound of the smoothing-weight search bracket (default: 1e12).

Returns:

(solution spectrum, iterations used, converged flag).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_rebunki.solve_rebunki(A: ndarray, b: ndarray, x0: ndarray, smoothing: float = 0.1, max_iterations: int = 1000, tolerance: float = 0.01, lethargy_weights: ndarray | None = None) tuple[ndarray, int, bool][source]#

Solve unfolding problem using the ReBUNKI (SPUNIT) algorithm.

This is the SPUNIT iteration of BUNKI/ReBUNKI; see bssunfold.core.unfold_bunki.solve_bunki() for the algorithm description. The default tolerance matches the ~1% relative-error convergence recommended for ReBUNKI.

Parameters:
  • A (np.ndarray) – Lethargy-weighted response matrix (m x n) as built by the Detector class.

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial spectrum guess (n,).

  • smoothing (float, optional) – Three-point smoothing factor (default: 0.1).

  • max_iterations (int, optional) – Maximum number of iterations (default: 1000).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 0.01).

  • lethargy_weights (np.ndarray, optional) – Per-bin lethargy widths. Only needed when A is supplied as a per-bin (non-lethargy-weighted) response matrix.

Returns:

(solution spectrum, iterations used, converged flag).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_nsduaz.solve_nsduaz(A: ndarray, b: ndarray, x0: ndarray, smoothing: float = 0.1, max_iterations: int = 1000, tolerance: float = 0.01, lethargy_weights: ndarray | None = None) tuple[ndarray, int, bool][source]#

Solve unfolding problem using the NSDUAZ (SPUNIT) iteration.

This is the SPUNIT iterative algorithm with the NSDUAZ default convergence tolerance (~1% relative change). See bssunfold.core.unfold_bunki.solve_bunki() for the iteration details. The initial spectrum x0 is typically obtained via select_catalogue_initial() (or provided by the user).

Parameters:
  • A (np.ndarray) – Lethargy-weighted response matrix (m x n) as built by the Detector class.

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial spectrum guess (n,).

  • smoothing (float, optional) – Three-point smoothing factor (default: 0.1).

  • max_iterations (int, optional) – Maximum number of iterations (default: 1000).

  • tolerance (float, optional) – Relative change tolerance for early stopping (default: 0.01).

  • lethargy_weights (np.ndarray, optional) – Per-bin lethargy widths. Only needed when A is supplied as a per-bin (non-lethargy-weighted) response matrix.

Returns:

(solution spectrum, iterations used, converged flag).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_randomized_kaczmarz.solve_randomized_kaczmarz(A: ndarray, b: ndarray, x0: ndarray, max_iterations: int = 1000, omega: float = 1.0, tolerance: float = 1e-06, random_state: int | None = None) tuple[ndarray, int, bool][source]#

Solve unfolding problem using the randomized Kaczmarz algorithm.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial guess (n,).

  • max_iterations (int, optional) – Maximum number of iterations (default: 1000).

  • omega (float, optional) – Relaxation parameter (0 < omega <= 2), default: 1.0.

  • tolerance (float, optional) – Convergence tolerance on ||x_k - x_{k-1}|| checked after each full sweep through the rows (default: 1e-6).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Tuple of (solution, iterations, converged).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_eki.solve_eki(A: ndarray, b: ndarray, x0: ndarray, n_ensemble: int = 50, n_iterations: int = 50, regularization: float = 0.0001, inflation: float = 1.02, noise_std: float | None = None, random_state: int | None = None) tuple[ndarray, int, bool][source]#

Solve unfolding problem using Ensemble Kalman Inversion.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • x0 (np.ndarray) – Initial guess (n,). Used as the centre of the initial ensemble.

  • n_ensemble (int, optional) – Number of ensemble members (default: 50).

  • n_iterations (int, optional) – Number of EKI iterations (default: 50).

  • regularization (float, optional) – Tikhonov-style regularization added to the covariance diagonal for numerical stability (default: 1e-4).

  • inflation (float, optional) – Covariance inflation factor applied after each update step to prevent ensemble collapse (default: 1.02).

  • noise_std (float, optional) – Standard deviation of measurement noise. If None, estimated as 5 % of ||b|| / sqrt(m).

  • random_state (int, optional) – Random seed for reproducibility.

Returns:

Tuple of (mean_spectrum, n_iterations, True).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_binned.solve_binned(A: ndarray, b: ndarray, bin_lookup: dict[str, Any], methods: dict[str, tuple[callable, dict]], x0: ndarray | None = None, timeout_per_method: float = 30.0) tuple[ndarray, dict[str, Any]][source]#

Run candidate methods and assemble a spectrum bin-by-bin.

Parameters:
  • A (ndarray, shape (m, n)) – Response matrix.

  • b (ndarray, shape (m,)) – Measurement vector.

  • bin_lookup (dict) – Pre-computed per-bin method ranking (from build_bin_lookup()).

  • methods (dict) – Mapping method_short (solver_callable, kwargs). Each callable must accept (A, b, x0=..., **kwargs) and return a spectrum array of shape (n,).

  • x0 (ndarray, optional) – Initial guess forwarded to every solver.

  • timeout_per_method (float) – Wall-clock timeout per method (seconds).

Returns:

  • spectrum (ndarray, shape (n,)) – Assembled spectrum.

  • meta (dict) – Metadata including method_map, successful_methods, and per-method spectra.

bssunfold.core.unfold_binned.build_bin_lookup(spectra_dir: str | Path, references_csv: str | Path, n_bins: int = 60, top_k: int = 5) dict[str, Any][source]#

Analyse benchmark unfolded spectra and build a per-bin method ranking.

Parameters:
  • spectra_dir (path) – Directory containing per-method .npz files (e.g. spectra/mc/).

  • references_csv (path) – CSV with reference spectra. Must contain a key column (hash) and at least n_bins numeric energy columns (energy_1energy_60 or the first N numeric columns).

  • n_bins (int) – Number of energy bins (default 60).

  • top_k (int) – Number of best methods to keep per bin.

Returns:

Dict with keys bin_to_methods (bin index -> list of (method_short, score) pairs), unique_methods and n_bins.

Return type:

dict

bssunfold.core.unfold_nnksvd.solve_nnksvd_unfold(A: ndarray, b: ndarray, x0: ndarray | None = None, n_atoms: int = 15, sparsity: int = 2, dictionary: ndarray | None = None, training_signals: ndarray | None = None, n_dictionary_iterations: int = 80, lambda_tik: float = 0.01, prior_wt: float = 0.5, sparse_coder: str = 'nnls_topk', random_state: int | None = None, tolerance: float = 1e-06, n_nnls_iter: int | None = None, E_MeV: ndarray | None = None) tuple[ndarray, int, bool][source]#

Unfold a neutron spectrum using the non-negative K-SVD pipeline.

Two operating modes:

  • Pre-learned dictionary (dictionary provided): the dictionary is used as-is; training_signals is ignored.

  • Online dictionary learning (training_signals provided or x0 used to synthesize them): the dictionary is learned on the fly with solve_nnksvd().

The forward model is y = A @ phi + eps and the spectrum is represented as phi = D @ alpha where D is the learned non-negative dictionary and alpha is a non-negative sparse coefficient vector. Sparse coding on the equivalent detection dictionary M_norm = normalize(A @ D) is performed with the selected sparse-coding strategy (NNLS+TopK, OMP, or NN-OMP).

Parameters:
  • A (np.ndarray) – Detector response matrix (m x n).

  • b (np.ndarray) – Measurement / count vector (m,).

  • x0 (np.ndarray, optional) – Initial spectrum guess (n,). Used to seed training signals when no training_signals is supplied.

  • n_atoms (int, optional) – Number of dictionary atoms (default: 15, the article’s optimum).

  • sparsity (int, optional) – Target sparsity K (default: 2, the article’s optimum).

  • dictionary (np.ndarray, optional) – Pre-learned non-negative dictionary (n x p). Bypasses online K-SVD training.

  • training_signals (np.ndarray, optional) – Training signals for online K-SVD (n x m). If not provided, log-spaced Gaussian bumps on the energy grid plus the initial guess are used.

  • n_dictionary_iterations (int, optional) – K-SVD iterations (default: 80, as in the article).

  • lambda_tik (float, optional) – Tikhonov regularization weight (default: 0.01).

  • prior_wt (float, optional) – Training-sample prior weight (default: 0.5).

  • sparse_coder (str, optional) – Sparse-coding strategy (default: "nnls_topk").

  • random_state (int, optional) – Random seed for reproducibility (default: 42 in the article).

  • tolerance (float, optional) – Convergence tolerance for K-SVD and OMP-style coders.

  • n_nnls_iter (int, optional) – Maximum NNLS iterations (passed through to scipy.optimize.nnls).

  • E_MeV (np.ndarray, optional) – Energy grid in MeV (n,). When provided, the default training signals are log-spaced Gaussian bumps on the log-energy grid, which ensures the dictionary covers the full spectral range. Falls back to a uniform normalised index when not supplied.

Returns:

Tuple (spectrum, iterations, converged).

Return type:

Tuple[np.ndarray, int, bool]

bssunfold.core.unfold_nnksvd.solve_nnksvd(signals: ndarray, n_atoms: int, n_iterations: int = 80, sparsity: int = 2, lambda_tik: float = 0.01, prior_wt: float = 0.5, sparse_coder: str = 'nnls_topk', random_state: int | None = None, tolerance: float = 1e-06) tuple[ndarray, ndarray][source]#

Non-negative K-SVD dictionary learning.

K-SVD variant with non-negativity constraints on both dictionary atoms and sparse coefficients, following Xu et al. (2026). The dictionary update stage applies non-negative truncation (max(0, atom)) after the SVD rank-1 update of each atom, then re-normalizes. The sparse coding stage uses one of the three strategies supported by this module (nnls_topk, omp or nn_omp).

Parameters:
  • signals (np.ndarray) – Training signals (n x m), one column per training sample. Must be non-negative (neutron spectra are physically non-negative).

  • n_atoms (int) – Number of dictionary atoms P.

  • n_iterations (int, optional) – Maximum K-SVD iterations (default: 80, as in the article).

  • sparsity (int, optional) – Target sparsity K for sparse coding (default: 2).

  • lambda_tik (float, optional) – Tikhonov weight for the NNLS+TopK sparse coder (default: 0.01).

  • prior_wt (float, optional) – Prior weight for the NNLS+TopK sparse coder (default: 0.5).

  • sparse_coder (str, optional) – Sparse-coding strategy: "nnls_topk", "omp" or "nn_omp" (default: "nnls_topk").

  • random_state (int, optional) – Random seed for reproducibility.

  • tolerance (float, optional) – Early-stopping tolerance on dictionary change.

Returns:

  • D (np.ndarray) – Learned non-negative dictionary (n x p), columns L2-normalized.

  • alpha_prior (np.ndarray) – Mean sparse code of the training signals (p,), used as the training-sample-driven prior during unfolding.

bssunfold.core.unfold_nnksvd.solve_nnls_topk(M_norm: ndarray, y: ndarray, sparsity: int, lambda_tik: float = 0.01, prior_wt: float = 0.0, alpha_prior: ndarray | None = None, max_iter: int | None = None) ndarray[source]#

NNLS+TopK sparse coding strategy (Xu et al. 2026, proposed method).

Three-stage hierarchical sparse coding:

  1. Global NNLS coarse solution: solve the Tikhonov-NNLS problem on the full dictionary.

  2. Top-K atom screening: keep the K atoms with the largest coefficients from the coarse solution.

  3. Local NNLS fine optimization: re-solve NNLS on the screened support for a refined, sparse, non-negative coefficient vector.

The hierarchical strategy avoids the cumulative selection error of greedy OMP-style algorithms and produces sparse, physically meaningful solutions.

Parameters:
  • M_norm (np.ndarray) – Normalized equivalent detection dictionary (m x p).

  • y (np.ndarray) – Measurement / count vector (m,).

  • sparsity (int) – Target sparsity K (number of non-zero coefficients).

  • lambda_tik (float, optional) – Tikhonov smoothing weight (default: 0.01).

  • prior_wt (float, optional) – Training-sample-driven prior weight (default: 0.0).

  • alpha_prior (np.ndarray, optional) – Prior coefficient vector (p,). Required when prior_wt > 0.

  • max_iter (int, optional) – Maximum NNLS iterations.

Returns:

Non-negative K-sparse coefficient vector (p,).

Return type:

np.ndarray

bssunfold.core.unfold_nnksvd.solve_nn_omp(D: ndarray, y: ndarray, sparsity: int, tolerance: float = 1e-06) ndarray[source]#

Non-negative Orthogonal Matching Pursuit (NN-OMP).

Greedy sparse coding with a non-negativity constraint on the coefficient vector. At each iteration:

  1. Pick the atom whose (signed) projection onto the residual is the largest positive value – non-negativity forbids negative coefficients so we only accept positively-correlated atoms.

  2. Solve NNLS on the selected support (instead of unconstrained LS).

  3. Update the residual.

Parameters:
  • D (np.ndarray) – Dictionary matrix (n x p).

  • y (np.ndarray) – Signal to be represented (n,).

  • sparsity (int) – Maximum number of non-zero coefficients (K in the article).

  • tolerance (float, optional) – Early-stopping residual tolerance (default: 1e-6).

Returns:

Non-negative sparse coefficient vector (p,).

Return type:

np.ndarray

bssunfold.core.unfold_nnksvd.solve_tikhonov_nnls(M_norm: ndarray, y: ndarray, lambda_tik: float = 0.01, prior_wt: float = 0.0, alpha_prior: ndarray | None = None, max_iter: int | None = None) ndarray[source]#

Tikhonov-regularized Non-Negative Least Squares.

Solves Eq. (2.5) of the article

min || y - M_norm @ alpha ||^2 + lambda_tik * || alpha ||^2 s.t. alpha >= 0

via the augmented-matrix equivalent (Eq. 2.6)

min || [y; 0] - [M_norm; sqrt(lambda_tik) I] @ alpha ||^2 s.t. alpha >= 0

An additional training-sample-driven prior constraint prior_wt * || alpha - alpha_prior ||^2 (article Section 2.2.2, “training sample-driven prior constraints”) is appended to the augmented system when prior_wt > 0 and alpha_prior is given.

Parameters:
  • M_norm (np.ndarray) – Normalized equivalent detection dictionary (m x p).

  • y (np.ndarray) – Measurement / count vector (m,).

  • lambda_tik (float, optional) – Tikhonov smoothing regularization weight (default: 0.01, as in the article).

  • prior_wt (float, optional) – Training-sample-driven prior weight (default: 0.0). When > 0, alpha_prior must be supplied.

  • alpha_prior (np.ndarray, optional) – Prior coefficient vector (p,). Required when prior_wt > 0.

  • max_iter (int, optional) – Maximum NNLS iterations.

Returns:

Non-negative sparse coefficient vector (p,).

Return type:

np.ndarray

Comparison Methods#

bssunfold.utils.comparison.compare_spectra(spectrum1: ndarray, spectrum2: ndarray, metrics: str | list[str] | None = None, bins: ndarray | None = None, energy: ndarray | None = None, cc_icrp116: dict[str, ndarray] | None = None, readings1: ndarray | None = None, readings2: ndarray | None = None, response_matrix: ndarray | None = None) dict[str, float][source]#

Compare two spectra using selected metrics.

Parameters:
  • spectrum1 (np.ndarray) – 1-D arrays of the same length.

  • spectrum2 (np.ndarray) – 1-D arrays of the same length.

  • metrics (str, list of str, or None) – Metric name(s). If None, all available metrics are computed (simple metrics only; pass energy to include EURADOS metrics).

  • bins (np.ndarray, optional) – Energy bins (unused, reserved for future use).

  • energy (np.ndarray, optional) – Energy grid in MeV. When provided, EURADOS-style metrics (dose differences, peak errors, etc.) are included automatically.

  • cc_icrp116 (np.ndarray, optional) – ICRP-116 conversion coefficients for dose calculations.

  • readings1 (np.ndarray, optional) – Measured readings for response-matrix consistency check.

  • readings2 (np.ndarray, optional) – Measured readings for response-matrix consistency check.

  • response_matrix (np.ndarray, optional) – Response matrix for consistency check.

Returns:

Mapping from metric name (short key) to computed value.

Return type:

Dict[str, float]

bssunfold.utils.comparison.compare_multiple(spectra: list[ndarray], metrics: str | list[str] | None = None, labels: list[str] | None = None) dict[str, dict[str, float]][source]#

Compare multiple spectra pairwise against the first one.

Parameters:
  • spectra (list of np.ndarray) – List of spectra. First entry is treated as reference.

  • metrics (str, list of str, or None) – Metric name(s). If None, all available metrics are computed.

  • labels (list of str, optional) – Labels for each spectrum.

Returns:

{label: {metric: value}} for each non-reference spectrum.

Return type:

Dict[str, Dict[str, float]]

Comparison Metrics#

Entropy-based#

bssunfold.utils.comparison.kl_divergence(p: ndarray, q: ndarray) float[source]#

Kullback–Leibler divergence D_KL(p || q).

Both inputs are normalized to probability distributions internally.

bssunfold.utils.comparison.cross_entropy(p: ndarray, q: ndarray) float[source]#

Cross-entropy H(p, q) = -sum(p * log(q)).

bssunfold.utils.comparison.entropy(p: ndarray) float[source]#

Shannon entropy H(p) = -sum(p * log(p)).

bssunfold.utils.comparison.entropy_difference_percent(p: ndarray, q: ndarray) float[source]#

Relative difference between cross-entropy and entropy in percent.

100 * (H(p,q) - H(p)) / H(p)

Distribution distances#

bssunfold.utils.comparison.wasserstein_dist(p: ndarray, q: ndarray) float[source]#

Wasserstein (earth mover’s) distance between two distributions.

Uses scipy.stats.wasserstein_distance.

bssunfold.utils.comparison.energy_dist(p: ndarray, q: ndarray) float[source]#

Energy distance between two distributions.

Uses scipy.stats.energy_distance.

bssunfold.utils.comparison.kolmogorov_smirnov_stat(p: ndarray, q: ndarray) float[source]#

Kolmogorov-Smirnov test statistic (D statistic).

Correlation#

bssunfold.utils.comparison.pearson_r(p: ndarray, q: ndarray) float[source]#

Pearson correlation coefficient.

Returns 0.0 if either input is constant (variance = 0).

bssunfold.utils.comparison.spearman_r(p: ndarray, q: ndarray) float[source]#

Spearman rank correlation coefficient.

Returns 0.0 if either input is constant (variance = 0).

Error metrics#

bssunfold.utils.comparison.mean_squared_error(p: ndarray, q: ndarray) float[source]#

Mean squared error.

bssunfold.utils.comparison.root_mean_squared_error(p: ndarray, q: ndarray) float[source]#

Root mean squared error.

bssunfold.utils.comparison.mean_absolute_error(p: ndarray, q: ndarray) float[source]#

Mean absolute error.

bssunfold.utils.comparison.mape(p: ndarray, q: ndarray) float[source]#

Mean absolute percentage error.

Returns percentage (0–100). Skips elements where p is near zero.

bssunfold.utils.comparison.r2_score(p: ndarray, q: ndarray) float[source]#

R-squared (coefficient of determination).

bssunfold.utils.comparison.max_error(p: ndarray, q: ndarray) float[source]#

Maximum residual error.

bssunfold.utils.comparison.median_absolute_error(p: ndarray, q: ndarray) float[source]#

Median absolute error.

Kernel / similarity#

bssunfold.utils.comparison.cosine_similarity(p: ndarray, q: ndarray) float[source]#

Cosine similarity between two vectors.

Returns 0 if either vector is zero-norm.

bssunfold.utils.comparison.mmd_rbf(p: ndarray, q: ndarray, gamma: float | None = None) float[source]#

Maximum Mean Discrepancy with RBF kernel.

Parameters:
  • p (np.ndarray) – 1-D arrays.

  • q (np.ndarray) – 1-D arrays.

  • gamma (float, optional) – RBF kernel width. If None, uses 1 / (2 * median_distance**2).

bssunfold.utils.comparison.total_flux_ratio(p: ndarray, q: ndarray) float[source]#

Ratio of total fluxes: sum(p) / sum(q).

1.0 = perfect conservation of total flux. > 1.0 = p overestimates total flux relative to q. < 1.0 = p underestimates total flux relative to q. Returns 0.0 if q (reference) flux is zero.

bssunfold.utils.comparison.spectral_shape_similarity(spectrum1: ndarray, spectrum2: ndarray) float[source]#

Similarity of normalized spectral shapes (0-1).

Computes cosine similarity of unit-normalized spectra.

Chi-squared family#

bssunfold.utils.comparison.chi_squared(p: ndarray, q: ndarray) float[source]#

Pearson’s chi-squared test statistic.

Internally normalizes both inputs as probability distributions.

bssunfold.utils.comparison.g_test(p: ndarray, q: ndarray) float[source]#

G-test (log-likelihood ratio) statistic.

bssunfold.utils.comparison.freeman_tukey(p: ndarray, q: ndarray) float[source]#

Freeman-Tukey statistic.

bssunfold.utils.comparison.cressie_read(p: ndarray, q: ndarray) float[source]#

Cressie-Read statistic.

Statistical tests#

bssunfold.utils.comparison.anderson_darling(p: ndarray, q: ndarray) float[source]#

Anderson-Darling test statistic for k-samples.

Returns 0.0 if either input is constant (all identical values).

bssunfold.utils.comparison.wilcoxon_test(p: ndarray, q: ndarray) float[source]#

Wilcoxon signed-rank test statistic.

Returns 0.0 if both inputs are identical (all differences zero).

bssunfold.utils.comparison.mannwhitneyu_test(p: ndarray, q: ndarray) float[source]#

Mann-Whitney U test statistic.

bssunfold.utils.comparison.standardized_mean_difference(p: ndarray, q: ndarray) float[source]#

Standardized mean difference (Cohen’s d).

SMD = (mean(p) - mean(q)) / sqrt((var(p) + var(q)) / 2)

Integral quantity metrics#

bssunfold.utils.comparison.fluence_averaged_energy(spectrum: ndarray, energy: ndarray) float[source]#

Fluence-averaged energy <E> of a single spectrum (MeV).

<E> = sum(E_i * Phi_i) / sum(Phi_i)

Returns 0.0 for a zero-total-flux spectrum.

bssunfold.utils.comparison.energy_group_fluence(spectrum: ndarray, energy: ndarray, thermal_max: float = 4e-07, epithermal_max: float = 0.1) dict[str, float][source]#

Fluence rate per energy group for a single spectrum.

Groups (EURADOS): thermal (E < 0.4 eV), epithermal (0.4 eV <= E < 0.1 MeV), fast (E >= 0.1 MeV). Returns absolute fluence sums (simple bin sums, matching energy_group_fluence_diff).

Parameters:
  • spectrum (np.ndarray) – Fluence per energy bin.

  • energy (np.ndarray) – Energy grid in MeV.

  • thermal_max (float) – Upper bound of thermal group in MeV (default: 0.4e-6 = 0.4 eV).

  • epithermal_max (float) – Upper bound of epithermal group in MeV (default: 0.1).

bssunfold.utils.comparison.dose_averaged_energy(spectrum: ndarray, energy: ndarray, cc_ade: dict[str, ndarray] | ndarray | None = None) float[source]#

Ambient dose equivalent-averaged energy <E>_H (MeV).

<E>_H = sum(E_i * H*(10)_i * Phi_i) / sum(H*(10)_i * Phi_i)

Uses ICRP-74 ADE conversion coefficients (ISO 2001) interpolated onto the energy grid, unless cc_ade is provided. Returns 0.0 for a zero-dose-weight spectrum.

bssunfold.utils.comparison.ambient_dose_equivalent_rate(spectrum: ndarray, energy: ndarray, cc_ade: dict[str, ndarray] | ndarray | None = None) float[source]#

Ambient dose equivalent rate H*(10) of a single spectrum.

H*(10) = sum(h*(10)_i * Phi_i * dlnE_i)

Uses ICRP-74 ADE conversion coefficients (ISO 2001) interpolated onto the energy grid, unless cc_ade is provided. Returns 0.0 for a zero-total-flux spectrum.

Spectral diagnostics (energy grid required)#

These metrics compare two spectra in physically meaningful terms (fluence, dose, energy groups, peaks) and are computed automatically by compare_spectra() when an energy grid is supplied.

bssunfold.utils.comparison.fluence_difference_percent(spectrum1: ndarray, spectrum2: ndarray, energy_bins: ndarray | None = None) float[source]#

Relative difference in total fluence between two spectra (%).

As used in EURADOS comparison: Δ(%) = 100 * (Q_participant - Q_reference) / Q_reference

Parameters:
  • spectrum1 (np.ndarray) – Spectra to compare (fluence per energy bin).

  • spectrum2 (np.ndarray) – Spectra to compare (fluence per energy bin).

  • energy_bins (np.ndarray, optional) – Energy bin widths. If None, assumes uniform weighting.

bssunfold.utils.comparison.energy_group_fluence_diff(spectrum1: ndarray, spectrum2: ndarray, energy: ndarray, thermal_max: float = 4e-07, epithermal_max: float = 0.1) dict[str, float][source]#

Relative difference in fluence for three energy groups (%).

Groups: thermal (E < 0.4 eV), epithermal (0.4 eV <= E < 0.1 MeV), fast (E >= 0.1 MeV).

Parameters:
  • spectrum1 (np.ndarray) – Spectra to compare.

  • spectrum2 (np.ndarray) – Spectra to compare.

  • energy (np.ndarray) – Energy grid in MeV.

  • thermal_max (float) – Upper bound of thermal group in MeV (default: 0.4e-6 = 0.4 eV).

  • epithermal_max (float) – Upper bound of epithermal group in MeV (default: 0.1).

bssunfold.utils.comparison.dose_difference_percent(spectrum1: ndarray, spectrum2: ndarray, energy: ndarray, cc_icrp116: dict[str, ndarray] | None = None) float[source]#

Relative difference in ambient dose equivalent H*(10) (%).

Parameters:
  • spectrum1 (np.ndarray) – Spectra to compare.

  • spectrum2 (np.ndarray) – Spectra to compare.

  • energy (np.ndarray) – Energy grid in MeV.

  • cc_icrp116 (np.ndarray, optional) – ICRP-116 conversion coefficients. If None, uses a simple approximation.

bssunfold.utils.comparison.fluence_averaged_energy_diff(spectrum1: ndarray, spectrum2: ndarray, energy: ndarray) float[source]#

Relative difference in fluence-averaged energy (%).

<E> = sum(E_i * Phi_i) / sum(Phi_i)

bssunfold.utils.comparison.dose_averaged_energy_diff(spectrum1: ndarray, spectrum2: ndarray, energy: ndarray, cc_icrp116: dict[str, ndarray] | None = None) float[source]#

Relative difference in H*(10)-averaged energy (%).

<E>_H = sum(E_i * H_i * Phi_i) / sum(H_i * Phi_i)

bssunfold.utils.comparison.log_lethargy_correlation(spectrum1: ndarray, spectrum2: ndarray, energy: ndarray) float[source]#

Pearson correlation in log(E)*Phi(E) coordinates.

As used in EURADOS figures showing spectra in lethargy representation.

bssunfold.utils.comparison.peak_location_error(spectrum1: ndarray, spectrum2: ndarray, energy: ndarray) float[source]#

Relative error in peak location (%).

Finds the energy of maximum flux in each spectrum and computes relative difference.

bssunfold.utils.comparison.peak_width_error(spectrum1: ndarray, spectrum2: ndarray, energy: ndarray) float[source]#

Relative error in peak width at half maximum (%).

Computes FWHM for each spectrum and returns relative difference.

bssunfold.utils.comparison.dose_weighted_error(spectrum1: ndarray, spectrum2: ndarray, energy: ndarray, cc_icrp116: dict[str, ndarray] | None = None) float[source]#

Dose-weighted mean squared error.

MSE weighted by dose contribution: sum(H_i * (s1_i - s2_i)^2) / sum(H_i)

bssunfold.utils.comparison.response_matrix_consistency(spectrum: ndarray, readings: ndarray, response_matrix: ndarray) float[source]#

Consistency between unfolded spectrum and measured readings.

Computes chi-squared: sum((R_measured - R_computed)^2 / R_measured) where R_computed = response_matrix @ spectrum.

Regularization Selection#

bssunfold.core.regularization.select_regularization_parameter(A: ndarray, b: ndarray, method: str = 'lcurve', noise_var: float | None = None, initial_spectrum: ndarray | None = None, **kwargs) float[source]#

Select regularization parameter using specified method.

Parameters:
  • A (np.ndarray) – Response matrix (m x n).

  • b (np.ndarray) – Measurement vector (m,).

  • method (str, optional) – Selection method: ‘lcurve’, ‘gcv’, ‘dp’, ‘cosine’ (default: ‘lcurve’).

  • noise_var (float, optional) – Noise variance for discrepancy principle.

  • initial_spectrum (np.ndarray, optional) – Initial spectrum for cosine similarity method.

  • **kwargs (dict) – Additional method-specific arguments.

Returns:

Selected regularization parameter (lambda).

Return type:

float

Raises:

ValueError – If method is unknown or selection fails.

bssunfold.core.regularization.lcurve_selection(A: ndarray, b: ndarray, n_alphas: int = 50, alpha_range: tuple[float, float] = (1e-09, 100.0)) float[source]#

Select regularization parameter using L-curve corner heuristic.

Parameters:
  • A (np.ndarray) – Response matrix.

  • b (np.ndarray) – Measurement vector.

  • n_alphas (int, optional) – Number of alpha values to test (default: 50).

  • alpha_range (Tuple[float, float], optional) – Range of alpha values (default: (1e-9, 1e2)).

Returns:

Selected regularization parameter.

Return type:

float

bssunfold.core.regularization.gcv_selection(A: ndarray, b: ndarray, n_alphas: int = 50, alpha_range: tuple[float, float] = (1e-09, 100.0)) float[source]#

Select regularization parameter using Generalized Cross Validation.

Parameters:
  • A (np.ndarray) – Response matrix.

  • b (np.ndarray) – Measurement vector.

  • n_alphas (int, optional) – Number of alpha values to test (default: 50).

  • alpha_range (Tuple[float, float], optional) – Range of alpha values (default: (1e-9, 1e2)).

Returns:

Selected regularization parameter.

Return type:

float

bssunfold.core.regularization.discrepancy_principle_selection(A: ndarray, b: ndarray, noise_var: float | None = None, n_alphas: int = 50, alpha_range: tuple[float, float] = (1e-09, 100.0)) float[source]#

Select regularization parameter using Discrepancy Principle.

Parameters:
  • A (np.ndarray) – Response matrix.

  • b (np.ndarray) – Measurement vector.

  • noise_var (float, optional) – Noise variance. If None, estimated from data.

  • n_alphas (int, optional) – Number of alpha values to test (default: 50).

  • alpha_range (Tuple[float, float], optional) – Range of alpha values (default: (1e-9, 1e2)).

Returns:

Selected regularization parameter.

Return type:

float

bssunfold.core.regularization.cosine_similarity_selection(A: ndarray, b: ndarray, initial_spectrum: ndarray, n_alphas: int = 100, alpha_range: tuple[float, float] = (-9, 2), norm: int = 2) float[source]#

Select regularization parameter by maximizing cosine similarity.

Uses precomputed SVD for efficient evaluation across alpha values.

Parameters:
  • A (np.ndarray) – Response matrix.

  • b (np.ndarray) – Measurement vector.

  • initial_spectrum (np.ndarray) – Initial/reference spectrum for similarity comparison.

  • n_alphas (int, optional) – Number of alpha values to test (default: 100).

  • alpha_range (Tuple[float, float], optional) – Log range of alpha values (default: (-9, 2)).

  • norm (int, optional) – Norm type for regularization (default: 2).

Returns:

Selected regularization parameter.

Return type:

float

bssunfold.core.regularization.quasi_optimality_selection(A: ndarray, b: ndarray, n_alphas: int = 50, alpha_range: tuple[float, float] = (1e-09, 100.0)) float[source]#

Select regularization parameter using the quasi-optimality criterion.

The quasi-optimality criterion (Hochstenbach & Reichel, 2015) minimises the noise component of the Tikhonov solution in the SVD basis:

Q(alpha) = sum_i (alpha^2 / (s_i^2 + alpha^2))^2 * (U_i^T b / s_i)^2

The optimal alpha is the one that minimises Q(alpha).

Parameters:
  • A (np.ndarray) – Response matrix.

  • b (np.ndarray) – Measurement vector.

  • n_alphas (int, optional) – Number of alpha values to test (default: 50).

  • alpha_range (Tuple[float, float], optional) – Range of alpha values (default: (1e-9, 1e2)).

Returns:

Selected regularization parameter.

Return type:

float

bssunfold.core.regularization.ncp_selection(A: ndarray, b: ndarray, n_alphas: int = 50, alpha_range: tuple[float, float] = (1e-09, 100.0), significance: float = 0.05) float[source]#

Select regularization parameter using the Normalized Cumulative Periodogram.

The NCP criterion tests whether the residuals of the regularised solution are consistent with white noise. For each candidate alpha, the residual vector is computed, its periodogram is formed, and a Kolmogorov-Smirnov test is applied against the uniform distribution on [0, 1]. The alpha with the smallest KS statistic (i.e. whitest residuals) is selected.

Parameters:
  • A (np.ndarray) – Response matrix.

  • b (np.ndarray) – Measurement vector.

  • n_alphas (int, optional) – Number of alpha values to test (default: 50).

  • alpha_range (Tuple[float, float], optional) – Range of alpha values (default: (1e-9, 1e2)).

  • significance (float, optional) – Reserved for future use (default: 0.05).

Returns:

Selected regularization parameter.

Return type:

float

bssunfold.core.regularization.snr_criterion_selection(A: ndarray, b: ndarray, n_alphas: int = 50, alpha_range: tuple[float, float] = (1e-09, 100.0)) float[source]#

Select regularization parameter by maximising signal-to-noise ratio.

For each candidate alpha the Tikhonov solution is split into a signal component (projection onto the leading singular vectors) and a noise component (projection onto the trailing singular vectors). The SNR is defined as the ratio of their squared Frobenius norms.

Parameters:
  • A (np.ndarray) – Response matrix.

  • b (np.ndarray) – Measurement vector.

  • n_alphas (int, optional) – Number of alpha values to test (default: 50).

  • alpha_range (Tuple[float, float], optional) – Range of alpha values (default: (1e-9, 1e2)).

Returns:

Selected regularization parameter.

Return type:

float

bssunfold.core.regularization.weighted_gcv_poisson_selection(A: ndarray, b: ndarray, n_alphas: int = 50, alpha_range: tuple[float, float] = (1e-09, 100.0)) float[source]#

Select regularization parameter using weighted GCV for Poisson noise.

Under Poisson noise the variance of each measurement equals its expectation. The weighted GCV replaces the ordinary GCV denominator ||r||^2 with sum(r_i^2 / w_i) where w_i = max(b_i, 1) are the Poisson variance estimates, and the trace term is replaced by tr(W (I - H_alpha)) with W = diag(1/w_i).

Parameters:
  • A (np.ndarray) – Response matrix.

  • b (np.ndarray) – Measurement vector.

  • n_alphas (int, optional) – Number of alpha values to test (default: 50).

  • alpha_range (Tuple[float, float], optional) – Range of alpha values (default: (1e-9, 1e2)).

Returns:

Selected regularization parameter.

Return type:

float

bssunfold.core.regularization.kfold_cv_selection(A: ndarray, b: ndarray, n_folds: int = 5, n_alphas: int = 50, alpha_range: tuple[float, float] = (1e-09, 100.0), random_state: int | None = None) float[source]#

Select regularization parameter using K-fold cross-validation.

The data is split into K folds. For each alpha, the Tikhonov problem is solved on K-1 folds and the held-out residual is evaluated. The alpha with the smallest mean held-out prediction error is selected.

Parameters:
  • A (np.ndarray) – Response matrix.

  • b (np.ndarray) – Measurement vector.

  • n_folds (int, optional) – Number of cross-validation folds (default: 5).

  • n_alphas (int, optional) – Number of alpha values to test (default: 50).

  • alpha_range (Tuple[float, float], optional) – Range of alpha values (default: (1e-9, 1e2)).

  • random_state (int, optional) – Random seed for fold assignment (default: None).

Returns:

Selected regularization parameter.

Return type:

float