Peak finding¶
COSEDA detects Bragg peaks from single-shot frames using peakfinder_8 or peakfinder_9, parallelized with Dask. Results are written back into the dataset HDF5 and summarized for QA. This stage must run before file stripping, center finding/refinement and indexing.
Algorithms¶
peakfinder_8 (pf8)¶
A connected-component finder from Diffractem. For each frame it:
Subtracts a local background estimated over an annular region (
local_bg_radius).Finds connected pixel groups that exceed an absolute threshold and a minimum SNR.
Accepts a group as a peak if its pixel count is within
[min_pix_count, max_pix_count].
Good default choice. Relies on a compiled C extension.
peakfinder_9 (pf9)¶
A pure-Python implementation compiled with Numba (@njit, parallel=True). For each candidate pixel it checks four conditions against the square ring of pixels at Chebyshev distance exactly window_radius:
The pixel must exceed every ring pixel by at least
min_peak_over_neighborsADU (strict local maximum).At least
max(1, 2·r−1)ring pixels must be valid (not masked).The pixel SNR must exceed
min_snr_max_pixelsigma above the ring mean.The integrated peak mass (sum of above-threshold pixel excesses within the window) must exceed
min_snr_whole_peaksigma.
Peaks are refined to sub-pixel accuracy with intensity-weighted centre-of-mass. No compiled C dependency; the Numba kernel is cached to disk after the first run.
Inputs¶
COSEDA working file (
<dataset>.h5) with:entry/data/images(required)/mask(2D pixel mask; same size as one frame) — required when running from the GUI. Generate one in the Preflight Check step before launching peak finding.optional
entry/data/center_x,center_y(used if you selectx0=y0=h5)
Dataset
.ini([Parameters]) with the algorithm-specific keys below
Processing steps (both algorithms)¶
For each frame (processed in batches):
Choose center
If
x0 = h5andy0 = h5: read per-frame centers fromentry/data/center_x,y.Otherwise: use the fixed
(x0, y0)from the INI for all frames.
Build a radial mask With pixel coordinates ((X,Y)) and center ((x_0, y_0)), [ R = \sqrt{(X-x_0)^2 + (Y-y_0)^2}. ] Keep pixels with
min_res ≤ R ≤ max_res. If/maskexists and is 2D with matching shape, multiply it in.Run the selected finder (see above for details)
Store fixed-length outputs For each frame, write:
entry/data/nPeaks(scalar)entry/data/peakXPosRaw,peakYPosRaw,peakTotalIntensity(each length 500 per frame; zero-padded if fewer than 500 peaks)
Batches are scheduled via Dask; progress is reported either to the console (ProgressBar) or to the GUI via a callback.
Outputs¶
Both algorithms write identical datasets:
HDF5:
entry/data/nPeaks— shape(N,)entry/data/peakXPosRaw,peakYPosRaw,peakTotalIntensity— shape(N, 500)
Run folder (created by the GUI):
findpeaks_*/peak_counts.npy— array[[frame_idx, nPeaks], ...](pf8)findpeaks9_*/peak_counts.npy— same format (pf9)*/paramdump.txt— parameters used (provenance)
Logs:
Peak count histogram buckets + an empty-frame warning into the dataset log
Statistics & QA¶
After writing results, COSEDA logs peak count statistics over four relative bins (0–25–50–75–100% of the observed max per file) and warns if >10% of frames are empty (suggesting to use Strip HDF5 to save disk and speed up downstream steps).
Parameters (INI [Parameters])¶
peakfinder_8¶
Key |
Description |
|---|---|
|
Absolute intensity threshold (ADU) |
|
Minimum signal-to-noise ratio |
|
Minimum connected pixels per peak |
|
Maximum connected pixels per peak |
|
Local background annulus radius (pixels) |
|
Inner radius of the search ring (pixels) |
|
Outer radius of the search ring (pixels) |
|
Beam centre in pixels, or |
Required keys check: the batch runner hard-fails if any of
min_snr, min_pix_count, max_pix_count, local_bg_radius, min_resis missing.
peakfinder_9¶
Key |
Description |
|---|---|
|
Half-side of the square background ring ( |
|
Floor on background std before SNR comparisons |
|
Required ADU excess over every ring pixel |
|
Required SNR of the peak pixel |
|
SNR threshold for pixels counted toward peak mass |
|
Required integrated peak-mass SNR |
|
Inner radius of the search ring (pixels) |
|
Outer radius of the search ring (pixels) |
|
Beam centre in pixels, or |
Both parameter sets can coexist in the same INI file; only the keys for the selected algorithm are read at run time.
Performance¶
Batching: frames are chunked (default batch size provided by GUI/CLI); each batch is a Dask delayed task.
Masking: combining
/maskand radial bounds reduces false positives.I/O: results are written once after all futures complete to minimize HDF5 overhead. Workers open the file with
locking=Falsefor safe concurrent read access.pf9 JIT compilation: the Numba kernel compiles on the first call (~3 s) and is cached to disk. Subsequent runs start immediately.
Using the GUI¶
Open the Peakfinding window.
Select the algorithm (peakfinder8 or peakfinder9) from the drop-down at the top. The parameter panel updates to show the relevant settings.
Set the parameters. Hover over any field for a tooltip explanation.
Optionally enable Live Preview to see peaks overlaid on the current frame as you adjust settings.
Click Current (or All Files) under Save Settings to persist the settings into the
.ini.Click Current (one dataset) or All Files (all loaded datasets) under Find Peaks to run.
After completion, review the logged peak statistics and
peak_counts.npyin the run folder.
The Find Peaks buttons are only enabled once all required parameters have been saved to the
.iniand a pixel mask exists in the HDF5. If a mask is missing, a dialog will prompt you to run the Preflight Check first.
CLI¶
# peakfinder_8
from coseda.peakfinding.findpeaks_dask import findpeaks_dask_batch
findpeaks_dask_batch("/path/to/dataset.ini", batch_size=1000)
# peakfinder_9
from coseda.peakfinding.peakfinder9 import findpeaks9_dask_batch
findpeaks9_dask_batch("/path/to/dataset.ini", batch_size=1000)
The GUI normally writes all parameters to the .ini before running; replicate that if calling programmatically.