pyfli.simulator.calibration.optimizer#

Simulation-based calibration of the pyfli simulator config.

Functions

_prior_bounds(names)

_reference_penalty(state, ctx)

reference_weight * sum(((prior mean - reference mean) / reference sd)^2) in physical units, so it does not depend on the prior's support (tau2_beta_range is re-centred between rounds).

active_photon_fraction(state, ctx)

Expected share of signal photons that land in active time bins, for the prior-mean lifetimes of state (photons in inactive bins are zeroed in data and simulation).

evaluate(state, ctx[, n, seed])

Simulate with state and return (distance, parts, sim_batch, sim_stats).

fit_priors_on_bank(base, ctx, names, n_bank, ...)

One bank round: simulate, global search (differential evolution), Nelder-Mead polish.

optimize_stage(base, ctx, names, max_evals, ...)

recenter_tau2_support(state[, margin])

Move tau2_beta_range to the fitted prior's 0.1-99.9 % range plus margin on each side, keeping the prior's mean and SD.

refresh_photon_prior(state, ctx)

run_calibration_rounds(state, ctx, nuisance, ...)

Alternate prior fits (bank) and IRF / detector fits (real simulations).

stage_parameter_names(state, ctx, ...)

(nuisance names searched with real simulations, prior names searched on the re-weighted bank).

Classes

CalibrationState(irf, priors, dcr[, ...])

ObjectiveContext(fm, detector_type, ...)

ParameterVector(base, ctx, names)

Maps a flat unconstrained vector to a CalibrationState and back.

PriorBank(state, ctx, n, seed[, uniform_share])

Simulated pixels from a broad proposal, re-weighted to any candidate set of Beta priors.

class CalibrationState(irf: IRFEstimate, priors: PriorSet, dcr: float, photon_scale: float = 1.0)[source]#

Bases: object

Parameters:
irf: IRFEstimate#
priors: PriorSet#
dcr: float#
photon_scale: float = 1.0#
a_range()[source]#
b_range()[source]#
class ObjectiveContext(fm: DecayForwardModel, detector_type: str, laser_freq_mhz: float, jitter: bool, comparator: StatsComparator, bg_bins: ndarray, exp_counts: ndarray, exp_peaks: ndarray, data_max: float, bit_depth: int | None, prior_inflation: float, n_sim: int, seed: int, reference_moments: dict = <factory>, reference_weight: float = 0.0, fixed_photon_prior: bool = False, inactive_bins: ndarray = <factory>)[source]#

Bases: object

Parameters:
fm: DecayForwardModel#
detector_type: str#
laser_freq_mhz: float#
jitter: bool#
comparator: StatsComparator#
bg_bins: ndarray#
exp_counts: ndarray#
exp_peaks: ndarray#
data_max: float#
bit_depth: int | None#
prior_inflation: float#
n_sim: int#
seed: int#
reference_moments: dict#
reference_weight: float = 0.0#
fixed_photon_prior: bool = False#
inactive_bins: ndarray#
active_photon_fraction(state, ctx)[source]#

Expected share of signal photons that land in active time bins, for the prior-mean lifetimes of state (photons in inactive bins are zeroed in data and simulation). 1 for continuous detectors or when every bin is active.

Parameters:
Return type:

float

refresh_photon_prior(state, ctx)[source]#
Parameters:
Return type:

CalibrationState

class ParameterVector(base, ctx, names)[source]#

Bases: object

Maps a flat unconstrained vector to a CalibrationState and back.

Parameters:
initial()[source]#
Return type:

ndarray

state(x)[source]#
Parameters:

x (ndarray)

Return type:

CalibrationState

evaluate(state, ctx, n=None, seed=None)[source]#

Simulate with state and return (distance, parts, sim_batch, sim_stats).

Parameters:
optimize_stage(base, ctx, names, max_evals, label)[source]#
Parameters:
Return type:

tuple[CalibrationState, list[dict]]

stage_parameter_names(state, ctx, optimize_irf, optimize_noise, optimize_priors, is_bi)[source]#

(nuisance names searched with real simulations, prior names searched on the re-weighted bank).

Parameters:
Return type:

tuple[list[str], list[str]]

class PriorBank(state, ctx, n, seed, uniform_share=0.3)[source]#

Bases: object

Simulated pixels from a broad proposal, re-weighted to any candidate set of Beta priors.

The bank is a defensive mixture: uniform_share of the pixels come from flat Beta(1, 1) priors on the current supports, the rest from the current priors widened about 4x in variance. For target priors pi each pixel gets the weight pi(theta) / q(theta), so the statistics of any candidate prior are obtained without re-simulating. IRF, noise and photon priors stay fixed inside one bank.

Parameters:
weights(priors)[source]#
Parameters:

priors (PriorSet)

Return type:

ndarray

distance(priors)[source]#
Parameters:

priors (PriorSet)

Return type:

tuple[float, dict, float]

recenter_tau2_support(state, margin=0.3)[source]#

Move tau2_beta_range to the fitted prior’s 0.1-99.9 % range plus margin on each side, keeping the prior’s mean and SD. Initial supports from noisy per-pixel fits are usually far too wide, which wastes the bank and makes the Beta very skewed.

Parameters:
Return type:

CalibrationState

fit_priors_on_bank(base, ctx, names, n_bank, max_evals, round_idx, min_ess=300.0)[source]#

One bank round: simulate, global search (differential evolution), Nelder-Mead polish.

Parameters:
Return type:

tuple[CalibrationState, list[dict]]

run_calibration_rounds(state, ctx, nuisance, prior_names, n_bank, rounds, max_evals_nuisance, max_evals_priors)[source]#

Alternate prior fits (bank) and IRF / detector fits (real simulations).

Parameters:
Return type:

tuple[CalibrationState, list[dict]]