pub fn parse_tof_sidecar_text(
text: &str,
n_frames: Option<usize>,
) -> Result<Vec<f64>, IoError>Expand description
Parse VENUS *_Spectra.txt sidecar text into TOF bin edges (µs).
Format: CSV shutter_time,counts where column 0 is the frame start
time in seconds — one row per TOF frame. Comment lines (#), blank
lines, and a single header row are tolerated (the
parse_spectrum_text rules).
Processing:
- start times must be finite, the first must be
>= 0, and the sequence must be strictly increasing; - values are converted to microseconds (
MICROSECONDS_PER_SECOND); - the closing edge of the last frame is synthesized by extrapolating
the last frame width (
last + (last − prev)), yielding N+1 ascending edges for N rows.
Bin uniformity is deliberately not enforced: VENUS MCP shutter segments change the frame width mid-run, so a sidecar with several distinct widths is valid. The last-segment-width extrapolation is exact whenever the final two frames belong to the same shutter segment (always the case in practice — segments are many frames long).
§shutter_time is the frame START (left bin edge) — evidence
Verified on measured IPTS-37432 VENUS autoreduce output (OB run 19385,
chunk id 116): the sidecar holds 4053 rows (exactly one per TIFF
frame), starting at 1.12 µs — not zero; the autoreduce already drops
the pre-trigger bins — in uniform 160 ns steps, and every time value
is an exact integer multiple of the 160 ns bin width
(1.12 µs = 7 × 0.16 µs). Bin centers would sit at half-multiples,
so shutter_time is definitively the frame start / left bin edge.
PLEIADES’s sidecar helper instead uses the values directly as frame
TOFs, which differs from the true bin centers by half a bin width;
NEREIDS uses edges here plus geometric-mean centers
(crate::tof::tof_edges_to_energy_centers). A constant offset of
this kind is absorbed by the fitted t₀ in the energy-scale fit.
§First edge exactly 0
A sidecar whose first start time is exactly 0 s parses successfully
(0 is a valid TOF edge), but that edge cannot be energy-converted —
E is undefined at t = 0. Crop the first frame from both the
stack and the edges (stack[1:], edges[1:]) before conversion.
Real autoreduce sidecars start after the pre-trigger bins, so this
only arises for hand-made files.
The returned edges plug directly into
crate::tof::tof_edges_to_energy_centers.
§Errors
IoError::InvalidParameter on fewer than 2 rows, non-finite or
unparseable values, a negative first start time, a non-increasing
sequence, or (when n_frames is Some) an edge/frame count mismatch.