Skip to main content

TabulatedResolution

Struct TabulatedResolution 

Source
pub struct TabulatedResolution { /* private fields */ }
Expand description

A tabulated resolution function from Monte Carlo instrument simulation.

Contains reference kernels R(Δt; E_ref) at discrete energies, stored in TOF-offset space (μs). Kernels are interpolated between reference energies and converted from TOF to energy space when applied.

§Offset orientation

Positive Δt = delayed emission (the moderator storage tail); the kernel mode sits at Δt = 0. At apply time the broadener gathers theory at t − Δt (convolution — see Self::broaden), so the positive-Δt tail reads theory from earlier TOF = higher energy and broadened dips acquire their tail toward lower apparent energy.

§File Format (VENUS/FTS)

FTS BL10 case i00dd folded triang FWHM 350 ns PSR   ← header
-----                                                 ← separator
   5.00000e-004   0.00000e+000                        ← energy block start
-53.458917835671329 2.051764258257523e-04             ← (tof_offset_μs, weight)
...
                                                      ← blank line separates blocks
   1.00000e-003   0.00000e+000                        ← next energy block
...

Implementations§

Source§

impl TabulatedResolution

Source

pub fn ref_energies(&self) -> &[f64]

Reference energies (eV), sorted ascending.

Source

pub fn kernels(&self) -> &[(Vec<f64>, Vec<f64>)]

For each reference energy: (tof_offsets_μs, weights) pairs. Weights are peak-normalized (max=1.0).

Source

pub fn flight_path_m(&self) -> f64

Flight path length in meters (needed for TOF↔energy conversion).

Source

pub fn detector_bin_probabilities( &self, true_energy_ev: f64, detector_time_edges_us: &[f64], timing_offset_us: f64, ) -> Result<Vec<f64>, ResolutionParseError>

Probability that a neutron of known true energy is recorded in each supplied detector-time bin.

The tabulated pulse is selected and interpolated at true_energy_ev; an energy outside the tabulated reference range uses the nearest reference kernel unchanged (the same clamping the broadening path applies). Its offsets are relative to the reference pulse mode, so the nominal arrival is timing_offset_us + TOF_FACTOR * flight_path_m / sqrt(E). timing_offset_us is the effective clock/energy-axis offset calibrated for the measurement; this method does not invent an absolute moderator emission time that is absent from a mode-centred UDR file.

The returned vector has one entry per adjacent edge pair and is not renormalized to the supplied window. Probability outside the measured window remains outside it; the quantified acquisition-window loss at this energy is one minus the sum of the returned vector (the pipeline-map contract’s R5·7 window-loss disclosure).

§Errors

Returns ResolutionParseError::InvalidFormat unless the true energy is positive and finite, the timing offset is finite, and at least two finite bin edges are supplied in strictly increasing order. It also fails if the interpolated tabulated pulse has zero area.

Source

pub fn width_corrected( &self, s0: f64, p: f64, e_ref: f64, ) -> Result<TabulatedResolution, ResolutionError>

Width-corrected copy of this tabulated kernel.

Shape-preserving instrument-resolution calibration knob: each reference-energy block’s TOF offsets are scaled by s(E) = s0 · (E / e_ref)^p about the block’s intensity centroid, so the kernel widens/narrows without moving its centroid — width and position stay orthogonal (t0/L handle absolute position). Weights are unchanged; the apply-time trapezoidal renormalization preserves unit area.

Exactness note: the orthogonality is exact at reference energies. Between references, interpolated_kernel’s width-normalized blend re-scales each block about the mode (offset 0), so the applied centroid picks up a second-order dependence on the width exponent p (measured ~1 % of σ for |p| ≤ 0.1 on widely spaced references) — absorbed by the jointly fitted t0 in calibration.

The pivot is the trapezoidal-weighted centroid Σ o·w·dt / Σ w·dt, using the same dt quadrature weights as the broadening integral (see Self::broaden). Because dt is itself affine in the offsets, the width scale multiplies every dt by s, so the integrated centroid is preserved exactly on any offset grid (uniform or not) — not just on uniform grids where the trapezoidal and plain centroids happen to coincide.

s0 = 1, p = 0 returns a width-identical copy. This is the fittable model behind the udr_corr resolution-calibration family: it trusts the Monte-Carlo shape and calibrates only its width / energy-dependence.

§Errors

Returns ResolutionError::InvalidWidthCorrection unless s0 is finite and > 0, e_ref is finite and > 0, and p is finite. A non-positive s0 would reverse/collapse the (ascending) offset ordering the broadening loop assumes, so it is rejected up front rather than silently clamped.

Source

pub fn with_flight_path( &self, flight_path_m: f64, ) -> Result<Self, ResolutionParseError>

The same kernel table read against a different flight path.

The stored offsets are times relative to this table’s own anchor, and the flight path enters only the TOF↔energy map they are applied through. So rebinding it is exact and needs no resynthesis — the kernel itself is a property of the moderator, not of how far the neutron then flew.

This is what a fitted L_scale requires: the data’s energy grid is built with L·L_scale, and a kernel still reading L applies a width wrong by that same factor.

§Errors

Returns ResolutionParseError::InvalidFormat if flight_path_m is not positive and finite.

Source

pub fn kernel_support_ev(&self, e_ev: f64) -> f64

Kernel support at energy e_ev, in eV: the larger of the two distances in Self::gather_bounds_ev. Returns 0.0 for non-positive or non-finite e_ev, an empty kernel set, or a non-positive flight path.

Source

pub fn gather_bounds_ev(&self, e_ev: f64) -> (f64, f64)

The lowest and highest energies the kernel at e_ev gathers theory from, as (low, high) in eV with low ≤ e_ev ≤ high, over the points Self::broaden keeps and in its arithmetic. Returns (e_ev, e_ev) for non-positive or non-finite e_ev, an empty kernel set, or a non-positive flight path.

Source§

impl TabulatedResolution

Source

pub fn from_text( text: &str, flight_path_m: f64, ) -> Result<Self, ResolutionParseError>

Parse a VENUS/FTS resolution file.

§Arguments
  • text — File contents as a string.
  • flight_path_m — Flight path length in meters.
Source

pub fn from_kernels( ref_energies: Vec<f64>, kernels: Vec<(Vec<f64>, Vec<f64>)>, flight_path_m: f64, ) -> Result<Self, ResolutionParseError>

Build a tabulated resolution directly from synthesized kernels.

Used by the analytical crate::ikeda_carpenter::IkedaCarpenter model, which generates (tof_offset_µs, weight) kernels at a set of reference energies and then rides the exact same broadening machinery as a Monte-Carlo file. Validates the same invariants from_text enforces: non-empty + strictly ascending reference energies, one kernel per energy, each kernel non-empty with matching offset/weight lengths, and all-finite offsets/weights.

§Errors

Returns ResolutionParseError::InvalidFormat if the flight path is not positive and finite, if the reference energies are empty / not strictly ascending, if the energy and kernel counts differ, if any kernel is empty, if a kernel’s offset and weight vectors differ in length, or if any offset/weight is non-finite.

Source

pub fn from_file( path: &str, flight_path_m: f64, ) -> Result<Self, ResolutionParseError>

Parse a VENUS/FTS resolution file from disk.

Source

pub fn broaden( &self, energies: &[f64], spectrum: &[f64], ) -> Result<Vec<f64>, ResolutionError>

Apply tabulated resolution broadening to a spectrum.

For each energy point:

  1. Find bracketing reference energies and interpolate kernel (log-space)
  2. Convert TOF offsets to energy offsets using exact TOF↔energy relation
  3. Convolve spectrum with interpolated kernel (trapezoidal integration)

Kernel points whose delayed-emission offset reaches the nominal flight time at the target energy (dt ≥ TOF(E)) gather from past infinite energy; they are dropped and the kernel renormalized over the surviving points, mirroring the grid-edge handling — see the tail-truncation note on broaden_presorted.

§Errors

Returns ResolutionError::LengthMismatch if the arrays differ in length, or ResolutionError::UnsortedEnergies if the energy grid is not sorted in non-descending order.

Source

pub fn plan(&self, energies: &[f64]) -> Result<ResolutionPlan, ResolutionError>

Build a reusable broadening plan for a specific target energy grid.

Validates that energies is non-descending — the same sorted-grid precondition enforced by TabulatedResolution::broaden via validate_inputs. An unsorted grid would produce a silently-wrong plan (misbracketed e_prime lookups against e_min / e_max), so it must be caught at build time rather than returning garbage from ResolutionPlan::apply.

The plan hoists every quantity that depends only on (target_energies, self.ref_energies, self.flight_path_m) — namely the TOF conversion, the log-space kernel interpolation, the per-kernel-point e_prime and spectrum-bracket lookup, and the trapezoidal integration widths. Applying the plan to a spectrum becomes a pure gather + multiply-add loop.

Build cost: same as one call to the private broaden_presorted helper (O(N_target × N_kernel) TOF / bracket / interp work, plus ~2 × N_kernel log-interp ops per target energy for interpolated_kernel). Apply cost per target: 1 branch + ~3 loads + 3 flops per retained entry, plus the final divide — typically < 10 % of the build cost. The payoff comes from reusing one plan across many spectra.

Bit-exact with broaden_presorted: pre-computes the same floating-point sequences (TOF, e_prime, dt_width, frac, weight, norm) in the same order.

§Errors

Returns ResolutionError::UnsortedEnergies if energies is not non-descending.

Trait Implementations§

Source§

impl Clone for TabulatedResolution

Source§

fn clone(&self) -> TabulatedResolution

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for TabulatedResolution

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more