Initial commit: grid-based multi-photon reconstruction
Code, configs, charge LUTs, best.pth and evaluation records for each training run, the knife-edge / Siemens-star / XRF notebooks with outputs, and the overnight run reports. Epoch checkpoints, inference results and HTML exports stay local (see .gitignore). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No files matched your search
@@ -0,0 +1,22 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.h5
|
||||
*.pdf
|
||||
# symlink to /mnt/sls_det_storage/.../InferenceResults (~19 GB)
|
||||
InferenceResults
|
||||
|
||||
# Notebooks: current versions with outputs; dated backups stay local
|
||||
Notebooks/Backup_*/
|
||||
|
||||
# Results: per run keep config, summaries, history, plots and best.pth;
|
||||
# epoch checkpoints and last.pth stay local
|
||||
Results/*_smoke_*/
|
||||
Results/*/Models/*
|
||||
!Results/*/Models/best.pth
|
||||
# energy_response.npz (~4.5 MB each) only where notebooks read it
|
||||
Results/*/energy_response.npz
|
||||
!Results/260919_poly3to30keV_Moench014_c96_00/energy_response.npz
|
||||
!Results/260927_poly2to20keV_Moench040_c96_00/energy_response.npz
|
||||
# overnight drivers: resume markers, and HTML exports of the tracked notebooks
|
||||
Results/overnight_*/state/
|
||||
Results/overnight_*/report/*.html
|
||||
@@ -0,0 +1,23 @@
|
||||
# WP1.1 -- alpha(E, t) / beta(E, t) look-up table, MOENCH014 @150 V
|
||||
#
|
||||
# The depth grid, and therefore the drift-time grid, depends only on the sensor,
|
||||
# so (energy, drift time) is a regular grid and needs no fitting in between.
|
||||
|
||||
sensor:
|
||||
code: Moench014
|
||||
hv: 150 # V
|
||||
thickness_um: 320
|
||||
depletion_voltage: 29.6 # V
|
||||
temperature: 307.8 # K, = 273 + 20.0 + 14.8, as in McGenerator
|
||||
|
||||
energies:
|
||||
first: 5 # keV
|
||||
last: 30
|
||||
step: 1
|
||||
|
||||
simulation:
|
||||
folder: /home/xie_x1/MLED/McSimulation/BatchResults/{sensor}_{hv}V_{energy}keV
|
||||
z_bins: 512
|
||||
method: simu2 # 'simu1' (cpu) or 'simu2' (gpu)
|
||||
|
||||
output: data/charge_lut_Moench014_150V.npz
|
||||
@@ -0,0 +1,23 @@
|
||||
# WP1.1 -- alpha(E, t) / beta(E, t) look-up table, MOENCH014 @150 V, 3-30 keV
|
||||
#
|
||||
# The depth grid, and therefore the drift-time grid, depends only on the sensor,
|
||||
# so (energy, drift time) is a regular grid and needs no fitting in between.
|
||||
|
||||
sensor:
|
||||
code: Moench014
|
||||
hv: 150 # V
|
||||
thickness_um: 320
|
||||
depletion_voltage: 29.6 # V
|
||||
temperature: 307.8 # K, = 273 + 20.0 + 14.8, as in McGenerator
|
||||
|
||||
energies:
|
||||
first: 3 # keV (2 keV exists but only 328/512 depth bins)
|
||||
last: 30
|
||||
step: 1
|
||||
|
||||
simulation:
|
||||
folder: /home/xie_x1/MLED/McSimulation/BatchResults/{sensor}_{hv}V_{energy}keV
|
||||
z_bins: 512
|
||||
method: simu2 # 'simu1' (cpu) or 'simu2' (gpu)
|
||||
|
||||
output: data/charge_lut_Moench014_150V_3to30keV.npz
|
||||
@@ -0,0 +1,32 @@
|
||||
# WP1.1 -- alpha(E, t) / beta(E, t) look-up table, MOENCH040 @150 V, 2-20 keV
|
||||
#
|
||||
# Same construction as charge_lut_Moench014_3to30keV.yaml; the sensor is the
|
||||
# 650 um MOENCH040 of the MaxIV knife edge (12 keV) and the SOLEIL Siemens star
|
||||
# (15 keV). Training range 2-20 keV by the user's choice (2026-09-27).
|
||||
#
|
||||
# The copied simulation lacks the deepest depth bins at 6 / 7 / 8 keV
|
||||
# (bins 266-511 / 475-511 / 492-511, next to the pixel side). At those energies
|
||||
# 1.4e-5 / 2.9e-6 / 1.3e-4 of the photons convert there; the bins are filled from
|
||||
# the 5 and 9 keV fits at the same depth (fill_missing: energy) and flagged in
|
||||
# the table as `filled_from_energy`.
|
||||
|
||||
sensor:
|
||||
code: Moench040
|
||||
hv: 150 # V
|
||||
thickness_um: 650
|
||||
depletion_voltage: 34.7 # V
|
||||
temperature: 307.8 # K, = 273 + 20.0 + 14.8, as in McGenerator
|
||||
|
||||
energies:
|
||||
first: 2
|
||||
last: 20
|
||||
step: 1
|
||||
|
||||
simulation:
|
||||
folder: /home/xie_x1/MLED/McSimulation/BatchResults/{sensor}_{hv}V_{energy}keV
|
||||
z_bins: 512
|
||||
method: simu2
|
||||
|
||||
fill_missing: energy
|
||||
|
||||
output: data/charge_lut_Moench040_150V_2to20keV.npz
|
||||
@@ -0,0 +1,63 @@
|
||||
# GridBased frame generation -- 12 keV, MOENCH040 @150 V (WP1.2, stamp-reuse variant)
|
||||
#
|
||||
# Frames are composed from the existing noiseless single-photon MC stamps
|
||||
# (McGeneration output). Charge superposition is linear, so pile-up frames can
|
||||
# be assembled by summing stamps; detector noise is applied once per frame.
|
||||
|
||||
meta:
|
||||
energy: 12 # keV, beam energy of the stamp library
|
||||
sensor: Moench040
|
||||
hv: 150 # V
|
||||
pixel_size_um: 25
|
||||
sensor_thickness_um: 650
|
||||
|
||||
stamps:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/Simulation/Moench040
|
||||
pattern: "12keV_Moench040_150V_{}.npz"
|
||||
train_files: [0, 11] # inclusive index range -> 12 shards
|
||||
val_files: [12, 13]
|
||||
test_files: [14, 15]
|
||||
|
||||
frame:
|
||||
size: 32 # training frame side (px). Fully-convolutional
|
||||
# model => inference runs on full 400x400 frames.
|
||||
margin: 4 # ring (px) over which photons are also thrown so
|
||||
# that out-of-frame photons leak charge in
|
||||
|
||||
noise:
|
||||
pixel_keV: 0.13 # per-pixel Gaussian, matches the iWoRiD study
|
||||
common_mode_row_keV: 0.0 # WP1.3: switch on once measured
|
||||
common_mode_col_keV: 0.0
|
||||
|
||||
edge_augmentation:
|
||||
fraction: 0.08 # fraction of frames containing a sensor boundary
|
||||
|
||||
output:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/GridBased/12keV_Moench040_150V
|
||||
|
||||
splits:
|
||||
train:
|
||||
frames_per_shard: 200_000 # 12 shards -> 2.4M frames, ~60M photons
|
||||
occupancy: {mode: loguniform, min: 0.002, max: 0.10}
|
||||
val:
|
||||
frames_per_shard: 80_000
|
||||
occupancy: {mode: loguniform, min: 0.002, max: 0.10}
|
||||
test:
|
||||
frames_per_shard: 80_000
|
||||
occupancy: {mode: loguniform, min: 0.002, max: 0.10}
|
||||
|
||||
# fixed-occupancy sets, for scanning performance vs flux
|
||||
eval_scan:
|
||||
# 20 % and 50 % are far outside the 0.2-10 % training range on purpose:
|
||||
# they are where the cluster chains stop working and the grid chain has to
|
||||
# be shown extrapolating. Appended, never reordered -- the per-point seed
|
||||
# is base_seed + 9000 + index, so inserting a point would reshuffle the
|
||||
# existing ones.
|
||||
occupancies: [0.005, 0.01, 0.02, 0.05, 0.10, 0.20, 0.50]
|
||||
frames_each: 8_000
|
||||
stamp_files: [14, 15]
|
||||
edge_fraction: 0.0
|
||||
|
||||
runtime:
|
||||
n_workers: 16
|
||||
seed: 20260830
|
||||
@@ -0,0 +1,65 @@
|
||||
# GridBased frame generation -- polychromatic 2-20 keV, MOENCH040 @150 V
|
||||
#
|
||||
# Same recipe as generate_frames_poly3to30keV_Moench014.yaml, for the 650 um
|
||||
# MOENCH040 of the 12 keV MaxIV knife edge and the 15 keV SOLEIL Siemens star:
|
||||
# per-photon energy (flat 2-20 keV), conversion depth from that energy's
|
||||
# attenuation length, and the charge cloud of alpha(E, t) / beta(E, t).
|
||||
# Pixel noise 0.13 keV = the 0.129 keV MOENCH040 delivers after the column
|
||||
# common mode (README, measurement pipeline).
|
||||
|
||||
meta:
|
||||
sensor: Moench040
|
||||
hv: 150 # V
|
||||
pixel_size_um: 25
|
||||
sensor_thickness_um: 650
|
||||
depletion_voltage: 34.7 # V
|
||||
temperature: 307.8 # K
|
||||
|
||||
generation:
|
||||
mode: lut
|
||||
lut: data/charge_lut_Moench040_150V_2to20keV.npz
|
||||
|
||||
spectrum:
|
||||
train: {mode: flat, min: 2.0, max: 20.0}
|
||||
val: {mode: flat, min: 2.0, max: 20.0}
|
||||
test: {mode: flat, min: 2.0, max: 20.0}
|
||||
eval: {mode: flat, min: 2.0, max: 20.0}
|
||||
|
||||
frame:
|
||||
size: 32
|
||||
margin: 4
|
||||
|
||||
noise:
|
||||
pixel_keV: 0.13
|
||||
common_mode_row_keV: 0.0
|
||||
common_mode_col_keV: 0.0
|
||||
|
||||
edge_augmentation:
|
||||
fraction: 0.08
|
||||
|
||||
output:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/GridBased/poly2to20keV_Moench040_150V
|
||||
|
||||
splits:
|
||||
train:
|
||||
n_shards: 12
|
||||
frames_per_shard: 100_000
|
||||
occupancy: {mode: loguniform, min: 0.002, max: 0.10}
|
||||
val:
|
||||
n_shards: 2
|
||||
frames_per_shard: 40_000
|
||||
occupancy: {mode: loguniform, min: 0.002, max: 0.10}
|
||||
test:
|
||||
n_shards: 2
|
||||
frames_per_shard: 40_000
|
||||
occupancy: {mode: loguniform, min: 0.002, max: 0.10}
|
||||
|
||||
eval_scan:
|
||||
occupancies: [0.005, 0.01, 0.02, 0.05, 0.10]
|
||||
frames_each: 8_000
|
||||
stamp_files: [0, 1]
|
||||
edge_fraction: 0.0
|
||||
|
||||
runtime:
|
||||
n_workers: 21
|
||||
seed: 20260927
|
||||
@@ -0,0 +1,70 @@
|
||||
# GridBased frame generation -- polychromatic 3-30 keV, MOENCH014 @150 V (WP1.2)
|
||||
#
|
||||
# Same as generate_frames_poly_Moench014.yaml except for the energy range: the
|
||||
# 5 keV edge biased and compressed Cr Ka (5.41 keV) in the XRF test, so the
|
||||
# lower edge moves to 3 keV, >= 1 keV below the lowest line of interest.
|
||||
#
|
||||
# Every photon gets its own energy, its own conversion depth from that energy's
|
||||
# attenuation length, and the charge cloud that the alpha(E, t) / beta(E, t)
|
||||
# table gives for the resulting drift time. The single-energy stamp-reuse path
|
||||
# is untouched and still lives in generate_frames_12keV.yaml.
|
||||
|
||||
meta:
|
||||
sensor: Moench014
|
||||
hv: 150 # V
|
||||
pixel_size_um: 25
|
||||
sensor_thickness_um: 320
|
||||
depletion_voltage: 29.6 # V
|
||||
temperature: 307.8 # K, = 273 + 20.0 + 14.8
|
||||
|
||||
generation:
|
||||
mode: lut
|
||||
lut: data/charge_lut_Moench014_150V_3to30keV.npz
|
||||
|
||||
spectrum:
|
||||
# flat, so the regression carries no spectral prior of its own; the table
|
||||
# covers 3-30 keV, and sampling to its edges means the outermost ~1 keV
|
||||
# regresses with a one-sided prior
|
||||
train: {mode: flat, min: 3.0, max: 30.0}
|
||||
val: {mode: flat, min: 3.0, max: 30.0}
|
||||
test: {mode: flat, min: 3.0, max: 30.0}
|
||||
eval: {mode: flat, min: 3.0, max: 30.0}
|
||||
|
||||
frame:
|
||||
size: 32
|
||||
margin: 4
|
||||
|
||||
noise:
|
||||
pixel_keV: 0.13
|
||||
common_mode_row_keV: 0.0
|
||||
common_mode_col_keV: 0.0
|
||||
|
||||
edge_augmentation:
|
||||
fraction: 0.08
|
||||
|
||||
output:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/GridBased/poly3to30keV_Moench014_150V
|
||||
|
||||
splits:
|
||||
train:
|
||||
n_shards: 12
|
||||
frames_per_shard: 100_000
|
||||
occupancy: {mode: loguniform, min: 0.002, max: 0.10}
|
||||
val:
|
||||
n_shards: 2
|
||||
frames_per_shard: 40_000
|
||||
occupancy: {mode: loguniform, min: 0.002, max: 0.10}
|
||||
test:
|
||||
n_shards: 2
|
||||
frames_per_shard: 40_000
|
||||
occupancy: {mode: loguniform, min: 0.002, max: 0.10}
|
||||
|
||||
eval_scan:
|
||||
occupancies: [0.005, 0.01, 0.02, 0.05, 0.10]
|
||||
frames_each: 8_000
|
||||
stamp_files: [0, 1]
|
||||
edge_fraction: 0.0
|
||||
|
||||
runtime:
|
||||
n_workers: 14
|
||||
seed: 20260918
|
||||
@@ -0,0 +1,66 @@
|
||||
# GridBased frame generation -- polychromatic 5-30 keV, MOENCH014 @150 V (WP1.2)
|
||||
#
|
||||
# Every photon gets its own energy, its own conversion depth from that energy's
|
||||
# attenuation length, and the charge cloud that the alpha(E, t) / beta(E, t)
|
||||
# table gives for the resulting drift time. The single-energy stamp-reuse path
|
||||
# is untouched and still lives in generate_frames_12keV.yaml.
|
||||
|
||||
meta:
|
||||
sensor: Moench014
|
||||
hv: 150 # V
|
||||
pixel_size_um: 25
|
||||
sensor_thickness_um: 320
|
||||
depletion_voltage: 29.6 # V
|
||||
temperature: 307.8 # K, = 273 + 20.0 + 14.8
|
||||
|
||||
generation:
|
||||
mode: lut
|
||||
lut: data/charge_lut_Moench014_150V.npz
|
||||
|
||||
spectrum:
|
||||
# flat, so the regression carries no spectral prior of its own; the table
|
||||
# covers 5-30 keV, and sampling to its edges means the outermost ~1 keV
|
||||
# regresses with a one-sided prior
|
||||
train: {mode: flat, min: 5.0, max: 30.0}
|
||||
val: {mode: flat, min: 5.0, max: 30.0}
|
||||
test: {mode: flat, min: 5.0, max: 30.0}
|
||||
eval: {mode: flat, min: 5.0, max: 30.0}
|
||||
|
||||
frame:
|
||||
size: 32
|
||||
margin: 4
|
||||
|
||||
noise:
|
||||
pixel_keV: 0.13
|
||||
common_mode_row_keV: 0.0
|
||||
common_mode_col_keV: 0.0
|
||||
|
||||
edge_augmentation:
|
||||
fraction: 0.08
|
||||
|
||||
output:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/GridBased/poly5to30keV_Moench014_150V
|
||||
|
||||
splits:
|
||||
train:
|
||||
n_shards: 12
|
||||
frames_per_shard: 100_000
|
||||
occupancy: {mode: loguniform, min: 0.002, max: 0.10}
|
||||
val:
|
||||
n_shards: 2
|
||||
frames_per_shard: 40_000
|
||||
occupancy: {mode: loguniform, min: 0.002, max: 0.10}
|
||||
test:
|
||||
n_shards: 2
|
||||
frames_per_shard: 40_000
|
||||
occupancy: {mode: loguniform, min: 0.002, max: 0.10}
|
||||
|
||||
eval_scan:
|
||||
occupancies: [0.005, 0.01, 0.02, 0.05, 0.10]
|
||||
frames_each: 8_000
|
||||
stamp_files: [0, 1]
|
||||
edge_fraction: 0.0
|
||||
|
||||
runtime:
|
||||
n_workers: 14
|
||||
seed: 20260901
|
||||
@@ -0,0 +1,97 @@
|
||||
# GridBased inference on measured data -- 12 keV, MOENCH040 @150 V (WP5.1/5.2)
|
||||
#
|
||||
# Raw ADU -> pedestal -> common mode -> 3D-LUT (all on GPU) -> GridNet -> photon
|
||||
# list -> sub-pixel binned image. No cluster finder, no calibrated frames on
|
||||
# disk. Select a run with --run <name>.
|
||||
|
||||
detector:
|
||||
n_x: 101
|
||||
n_y: 101
|
||||
corner: [70, 170] # StCorner: ROI position inside the 400x400 chip,
|
||||
# needed to crop the calibration LUT
|
||||
pixel_size_um: 25.0
|
||||
header_words: 56
|
||||
|
||||
calibration:
|
||||
file: /home/xie_x1/MLED/data-process/utils/BacksidePulsing_Calibration/Moench040/Moench040_AduToKevMapping_g4_50us_150V_250423.npy
|
||||
common_mode: column # MOENCH is column-parallel: 6.7 ADU RMS column
|
||||
# offset. Correcting it takes the per-pixel noise
|
||||
# from 0.140 to 0.129 keV -- i.e. onto the 0.13 keV
|
||||
# the model was trained with.
|
||||
pedestal_source: pedestal_run # 'pedestal_run' or 'per_file' (self-median)
|
||||
pedestal_frames: 2000
|
||||
|
||||
model:
|
||||
# All eight measurement runs are reconstructed with this one checkpoint so
|
||||
# that the flux points, and the edge/flat pair within each point, are
|
||||
# comparable. Override per run with --checkpoint only for tests.
|
||||
checkpoint: /home/xie_x1/MLXID/GridBased/Results/260831_12keV_Moench040_01/Models/best.pth
|
||||
threshold: 0.3
|
||||
merge_distance: 0.1
|
||||
|
||||
inference:
|
||||
n_frames: null # null = the whole run
|
||||
batch_size: 512
|
||||
binning_factor: 10 # 25 um / 10 = 2.5 um bins, as in the cluster-based analysis
|
||||
save_photons: false # 1.9e8 photons for the full run -> ~3 GB
|
||||
self_flattening: true # Rosenblatt remap of the sub-pixel phase (risk R1)
|
||||
energy_bins: [0.0, 40.0, 400]
|
||||
output_folder: /mnt/sls_det_storage/moench_data/MLXID/InferenceResults/GridBased
|
||||
|
||||
runs:
|
||||
Edge_3filters_pos0_12keV:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_3filters_pos0_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_3filters_pos0_data_d0_f{}_0.raw
|
||||
signal_files: [0, 139]
|
||||
|
||||
Flat_3filters_pos0_12keV:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_3filters_pos0_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_3filters_pos0_data_d0_f{}_0.raw
|
||||
signal_files: [0, 139]
|
||||
|
||||
|
||||
Edge_0filters_12keV: # 9.42 % occupancy in the illuminated area
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_0filters_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_0filters_data_d0_f{}_0.raw
|
||||
signal_files: [0, 34]
|
||||
|
||||
Flat_0filters_12keV:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_0filters_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_0filters_data_d0_f{}_0.raw
|
||||
signal_files: [0, 34]
|
||||
|
||||
Edge_1filters_12keV: # 3.90 % occupancy in the illuminated area
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_1filters_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_1filters_data_d0_f{}_0.raw
|
||||
signal_files: [0, 69]
|
||||
|
||||
Flat_1filters_12keV:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_1filters_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_1filters_data_d0_f{}_0.raw
|
||||
signal_files: [0, 69]
|
||||
|
||||
Edge_2filters_12keV: # 1.58 %
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_2filters_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_2filters_data_d0_f{}_0.raw
|
||||
signal_files: [0, 69]
|
||||
|
||||
Flat_2filters_12keV:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_2filters_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_2filters_data_d0_f{}_0.raw
|
||||
signal_files: [0, 69]
|
||||
|
||||
Pedestal_1filters_12keV: # dark run: the model must find (almost) nothing
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_1filters_pedestal_d0_f0_0.raw # a different run's pedestal,
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_1filters_pedestal_d0_f{}_0.raw # so the test is independent
|
||||
signal_files: [0, 0]
|
||||
|
||||
Pedestal_2filters_12keV:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_2filters_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_2filters_pedestal_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
|
||||
# dark run: the model must find (almost) nothing here -- the hardest fake-rate test
|
||||
Pedestal_3filters_pos0_12keV:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_3filters_pos0_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_3filters_pos0_pedestal_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
@@ -0,0 +1,210 @@
|
||||
# GridBased inference on measured data -- XRF, MOENCH014 @150 V, poly 3-30 keV model
|
||||
#
|
||||
# 2603 MaxIV beamtime, process/xrf. Every run is a flood field on the full
|
||||
# 400x400 chip (fluorescence is isotropic, no imaging optics), so these runs
|
||||
# test the energy axis and the flux behaviour, not spatial resolution:
|
||||
# * line positions / widths against tabulated energies (per run, `lines`)
|
||||
# * Kalpha pairs a few keV apart must come out resolved
|
||||
# * line positions and pile-up versus flux (factor 10 -> 1)
|
||||
# * sub-pixel flatness of a uniform illumination (self_flattening)
|
||||
# * fake rate on a dark run
|
||||
#
|
||||
# `factor` is the slit factor of the acquisition script: gap = 1.1 mm / factor,
|
||||
# so factor 1 is the highest flux. Each data file holds 100 000 frames, each
|
||||
# pedestal file 1000 frames taken ~3 min before its data run.
|
||||
#
|
||||
# Survey of all 58 runs (2000 frames each, 3x3-sum local maxima; see the
|
||||
# comments per run): pixel noise after column common mode 0.126 keV (0.144 on
|
||||
# AgCd), matching the 0.13 keV of the training frames; occupancy 0.6-7 %, all
|
||||
# inside the 0.2-10 % training range. Beam was 12 keV for the Cu/Cr/Co and
|
||||
# pigment runs (elastic line at 12.0 keV); for the Ag runs it was above the Sb
|
||||
# K edge (30.5 keV), and their Compton/elastic bump at ~28.5-29 keV sits at the
|
||||
# top of the training range.
|
||||
#
|
||||
# `lines` are Kalpha1/Kalpha2 centroids (2:1) and Kbeta1 in keV, for the
|
||||
# downstream line fit; 05_infer_measurement.py ignores them.
|
||||
#
|
||||
# The Moench014 LUT has 1640 bins, the abs()/sign() convention of
|
||||
# UsefulFuncs.convertAduFrameToEnergyFrame; GpuCalibrator handles it.
|
||||
|
||||
detector:
|
||||
n_x: 400
|
||||
n_y: 400
|
||||
corner: [0, 0] # full chip, the LUT is used uncropped
|
||||
pixel_size_um: 25.0
|
||||
header_words: 56
|
||||
|
||||
calibration:
|
||||
file: /home/xie_x1/MLED/data-process/utils/BacksidePulsing_Calibration/Moench014/Moench014_AduToKevMapping_g4_50us_250305.npy
|
||||
common_mode: column_masked # median over the pixels without charge. The plain
|
||||
# column median is pulled up by the photons: -4.0 /
|
||||
# -7.2 meV per pixel on AgMo / CuCrCo factor 10,
|
||||
# i.e. -36 / -65 meV on a 3x3 sum, growing with flux
|
||||
pedestal_source: pedestal_run
|
||||
pedestal_frames: 1000 # all a pedestal file has
|
||||
|
||||
model:
|
||||
# 3-30 keV, [32, 64, 96, 96], chosen 2026-09-19 from the four sizes in
|
||||
# Results/overnight_poly3to30keV/report. The previous default, 5-30 keV
|
||||
# [32, 64, 128, 128], is Results/260901_poly5to30keV_Moench014_00; its XRF
|
||||
# reconstructions carry the tag _poly5to30.
|
||||
checkpoint: /home/xie_x1/MLXID/GridBased/Results/260919_poly3to30keV_Moench014_c96_00/Models/best.pth
|
||||
threshold: 0.3
|
||||
merge_distance: 0.1
|
||||
|
||||
inference:
|
||||
n_frames: null # null = the whole run
|
||||
precision: fp16 # FP16 autocast + channels-last; offsets and energy of
|
||||
# the candidate cells recomputed in FP32 (an FP16 head
|
||||
# rounds E to 7-15 meV steps: a comb in 50 eV spectra).
|
||||
# Photon list = FP32 within ~20 nm / ~4 meV.
|
||||
batch_size: 32 # 2.6 GB peak for the model in FP16 (7.9 GB in FP32);
|
||||
# larger batches are not faster
|
||||
binning_factor: 10
|
||||
save_photons: false # ~1.8e8 photons per run at factor 10 -> ~3 GB
|
||||
self_flattening: true # the 'before' phase histogram of a flood field is
|
||||
# the direct R1 measurement
|
||||
energy_bins: [0.0, 40.0, 800] # 0.05 keV, for fitting line positions
|
||||
output_folder: /mnt/sls_det_storage/moench_data/MLXID/InferenceResults/GridBased/XRF_2603MaxIV
|
||||
|
||||
runs:
|
||||
# --- two elements, Kalpha lines well separated --------------------------
|
||||
|
||||
# Mo Ka 17.44 / Ag Ka 22.11: 4.7 keV apart, mid-range, with both Kbeta lines
|
||||
# resolved as well -- the cleanest multi-line run. Full flux series.
|
||||
AgMo_1_factor_10: # occupancy 0.75 %
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/AgMo_1_factor_10_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/AgMo_1_factor_10_data_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
lines: {Mo_Ka: 17.44, Mo_Kb: 19.61, Ag_Ka: 22.11, Ag_Kb: 24.94}
|
||||
|
||||
AgMo_1_factor_4: # 1.4 %
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/AgMo_1_factor_4_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/AgMo_1_factor_4_data_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
lines: {Mo_Ka: 17.44, Mo_Kb: 19.61, Ag_Ka: 22.11, Ag_Kb: 24.94}
|
||||
|
||||
AgMo_1_factor_2: # 2.5 %
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/AgMo_1_factor_2_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/AgMo_1_factor_2_data_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
lines: {Mo_Ka: 17.44, Mo_Kb: 19.61, Ag_Ka: 22.11, Ag_Kb: 24.94}
|
||||
|
||||
# with the plain column median the 3x3-sum centroids here sat 0.06-0.07 keV
|
||||
# below factor 10 (median biased by the hits); column_masked removes that
|
||||
AgMo_1_factor_1: # 4.0 %
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/AgMo_1_factor_1_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/AgMo_1_factor_1_data_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
lines: {Mo_Ka: 17.44, Mo_Kb: 19.61, Ag_Ka: 22.11, Ag_Kb: 24.94}
|
||||
|
||||
# Ag Ka 22.11 / Sb Ka 26.28: 4.2 keV apart. Sb Kb 29.73 merges with the
|
||||
# scatter bump at the top edge of the training range.
|
||||
AgSb_1_factor_10: # 0.70 %
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/AgSb_1_factor_10_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/AgSb_1_factor_10_data_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
lines: {Ag_Ka: 22.11, Ag_Kb: 24.94, Sb_Ka: 26.28, Sb_Kb: 29.73}
|
||||
|
||||
# Cr Ka 5.41 / Cu Ka 8.04: 2.6 keV apart, at the low end. Cr Ka was 0.4 keV
|
||||
# above the training edge of the 5-30 keV model (+33 meV, width compressed);
|
||||
# the 3-30 keV model puts it 2.4 keV inside its range. CuCr_1..4 are the same pair
|
||||
# at different Cr:Cu ratios (3x3-sum peak heights 17 : 4.2 : 1.2 : 0.43).
|
||||
CuCr_1_factor_10: # 1.0 %, Cr-dominated
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/CuCr_1_factor_10_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/CuCr_1_factor_10_data_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
lines: {Cr_Ka: 5.41, Cr_Kb: 5.95, Cu_Ka: 8.04, Cu_Kb: 8.91, elastic: 12.0}
|
||||
|
||||
CuCr_2_factor_10: # 1.0 %
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/CuCr_2_factor_10_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/CuCr_2_factor_10_data_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
lines: {Cr_Ka: 5.41, Cr_Kb: 5.95, Cu_Ka: 8.04, Cu_Kb: 8.91, elastic: 12.0}
|
||||
|
||||
CuCr_3_factor_10: # 1.2 %, Cr and Cu about equal
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/CuCr_3_factor_10_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/CuCr_3_factor_10_data_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
lines: {Cr_Ka: 5.41, Cr_Kb: 5.95, Cu_Ka: 8.04, Cu_Kb: 8.91, elastic: 12.0}
|
||||
|
||||
CuCr_4_factor_10: # 1.2 %, Cu-dominated
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/CuCr_4_factor_10_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/CuCr_4_factor_10_data_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
lines: {Cr_Ka: 5.41, Cr_Kb: 5.95, Cu_Ka: 8.04, Cu_Kb: 8.91, elastic: 12.0}
|
||||
|
||||
# --- three elements ------------------------------------------------------
|
||||
|
||||
# Cr Ka 5.41 / Co Ka 6.93 / Cu Ka 8.04: 1.5 and 1.1 keV apart, and Co Kb 7.65
|
||||
# sits on the low flank of Cu Ka -- in the 3x3 sums Cu is only a shoulder.
|
||||
# Pg17 / Pg28 / Cu below are the single-line references for it.
|
||||
# Full flux series.
|
||||
CuCrCo_1_factor_10: # 1.2 %
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/CuCrCo_1_factor_10_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/CuCrCo_1_factor_10_data_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
lines: {Cr_Ka: 5.41, Cr_Kb: 5.95, Co_Ka: 6.93, Co_Kb: 7.65, Cu_Ka: 8.04, Cu_Kb: 8.91, elastic: 12.0}
|
||||
|
||||
CuCrCo_1_factor_4: # 2.2 %
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/CuCrCo_1_factor_4_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/CuCrCo_1_factor_4_data_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
lines: {Cr_Ka: 5.41, Cr_Kb: 5.95, Co_Ka: 6.93, Co_Kb: 7.65, Cu_Ka: 8.04, Cu_Kb: 8.91, elastic: 12.0}
|
||||
|
||||
CuCrCo_1_factor_2: # 3.9 %
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/CuCrCo_1_factor_2_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/CuCrCo_1_factor_2_data_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
lines: {Cr_Ka: 5.41, Cr_Kb: 5.95, Co_Ka: 6.93, Co_Kb: 7.65, Cu_Ka: 8.04, Cu_Kb: 8.91, elastic: 12.0}
|
||||
|
||||
CuCrCo_1_factor_1: # 5.9 %
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/CuCrCo_1_factor_1_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/CuCrCo_1_factor_1_data_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
lines: {Cr_Ka: 5.41, Cr_Kb: 5.95, Co_Ka: 6.93, Co_Kb: 7.65, Cu_Ka: 8.04, Cu_Kb: 8.91, elastic: 12.0}
|
||||
|
||||
# --- single-line references ---------------------------------------------
|
||||
# One fluorescence line plus the 12 keV elastic line: energy scale and
|
||||
# resolution at each of the CuCrCo energies without overlaps. In the 3x3
|
||||
# sums each also shows a pile-up peak at twice its line (10.8 / 13.8 /
|
||||
# 15.9 keV); a photon-separating reconstruction should shrink it.
|
||||
|
||||
Pg17_factor_10: # 1.6 %, pigment green 17 (Cr2O3)
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/Pg17_factor_10_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/Pg17_factor_10_data_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
lines: {Cr_Ka: 5.41, Cr_Kb: 5.95, elastic: 12.0}
|
||||
|
||||
Pg28_factor_10: # 1.1 %, pigment green 28 (cobalt titanate; Ti Ka
|
||||
# 4.51 is below the training range)
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/Pg28_factor_10_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/Pg28_factor_10_data_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
lines: {Co_Ka: 6.93, Co_Kb: 7.65, elastic: 12.0}
|
||||
|
||||
Cu_factor_10: # 1.5 %
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/Cu_factor_10_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/Cu_factor_10_data_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
lines: {Cu_Ka: 8.04, Cu_Kb: 8.91, elastic: 12.0}
|
||||
|
||||
# --- resolution limit ------------------------------------------------------
|
||||
|
||||
# Ag Ka 22.11 / Cd Ka 23.11: only 1.0 keV apart, merged into one peak in the
|
||||
# 3x3 sums. Highest noise of the set (0.144 keV).
|
||||
AgCd_1_factor_10: # 1.4 %
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/AgCd_1_factor_10_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/AgCd_1_factor_10_data_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
lines: {Ag_Ka: 22.11, Cd_Ka: 23.11, Ag_Kb: 24.94, Cd_Kb: 26.10}
|
||||
|
||||
# --- dark run ----------------------------------------------------------------
|
||||
|
||||
# the shutter is closed during pedestal runs: the model must find (almost)
|
||||
# nothing. Pedestal from the run taken 3 min earlier, so the test is
|
||||
# independent of the frames it is applied to.
|
||||
Pedestal_CuCrCo_1:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/CuCrCo_1_factor_4_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/xrf/CuCrCo_1_factor_10_pedestal_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
@@ -0,0 +1,96 @@
|
||||
# GridBased inference on measured data -- 12 keV knife edge, MOENCH040 @150 V,
|
||||
# with the polychromatic 2-20 keV model (overnight 2026-09-27/28)
|
||||
#
|
||||
# Identical to infer_measurement_12keV.yaml -- same runs, same ROI readout, same
|
||||
# pedestal, same column common mode, same self-flattening -- so that the only
|
||||
# difference from the published 12 keV GridBased images is the model. Only the
|
||||
# precision differs: FP16 with the energy head in FP32 (predict_fp16), as for
|
||||
# every poly model. The checkpoint is passed with --checkpoint by
|
||||
# scripts/overnight_poly2to20keV_Moench040_partB.sh and the outputs carry the tag
|
||||
# _poly2to20, next to the 12 keV model's.
|
||||
|
||||
detector:
|
||||
n_x: 101
|
||||
n_y: 101
|
||||
corner: [70, 170] # StCorner: ROI position inside the 400x400 chip
|
||||
pixel_size_um: 25.0
|
||||
header_words: 56
|
||||
|
||||
calibration:
|
||||
file: /home/xie_x1/MLED/data-process/utils/BacksidePulsing_Calibration/Moench040/Moench040_AduToKevMapping_g4_50us_150V_250423.npy
|
||||
common_mode: column # as for the 12 keV model's runs
|
||||
pedestal_source: pedestal_run
|
||||
pedestal_frames: 2000
|
||||
|
||||
model:
|
||||
checkpoint: null # given on the command line (--checkpoint)
|
||||
threshold: 0.3
|
||||
merge_distance: 0.1
|
||||
|
||||
inference:
|
||||
n_frames: null # null = the whole run
|
||||
precision: fp16 # FP16 backbone, FP32 energy/offsets of the candidates
|
||||
batch_size: 512
|
||||
binning_factor: 10 # 2.5 um bins
|
||||
save_photons: false
|
||||
self_flattening: true
|
||||
energy_bins: [0.0, 30.0, 600] # 50 eV
|
||||
output_folder: /mnt/sls_det_storage/moench_data/MLXID/InferenceResults/GridBased
|
||||
|
||||
runs:
|
||||
Edge_3filters_pos0_12keV:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_3filters_pos0_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_3filters_pos0_data_d0_f{}_0.raw
|
||||
signal_files: [0, 139]
|
||||
|
||||
Flat_3filters_pos0_12keV:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_3filters_pos0_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_3filters_pos0_data_d0_f{}_0.raw
|
||||
signal_files: [0, 139]
|
||||
|
||||
|
||||
Edge_0filters_12keV: # 9.42 % occupancy in the illuminated area
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_0filters_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_0filters_data_d0_f{}_0.raw
|
||||
signal_files: [0, 34]
|
||||
|
||||
Flat_0filters_12keV:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_0filters_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_0filters_data_d0_f{}_0.raw
|
||||
signal_files: [0, 34]
|
||||
|
||||
Edge_1filters_12keV: # 3.90 % occupancy in the illuminated area
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_1filters_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_1filters_data_d0_f{}_0.raw
|
||||
signal_files: [0, 69]
|
||||
|
||||
Flat_1filters_12keV:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_1filters_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_1filters_data_d0_f{}_0.raw
|
||||
signal_files: [0, 69]
|
||||
|
||||
Edge_2filters_12keV: # 1.58 %
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_2filters_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_2filters_data_d0_f{}_0.raw
|
||||
signal_files: [0, 69]
|
||||
|
||||
Flat_2filters_12keV:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_2filters_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_2filters_data_d0_f{}_0.raw
|
||||
signal_files: [0, 69]
|
||||
|
||||
Pedestal_1filters_12keV: # dark run: the model must find (almost) nothing
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_1filters_pedestal_d0_f0_0.raw # a different run's pedestal,
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_1filters_pedestal_d0_f{}_0.raw # so the test is independent
|
||||
signal_files: [0, 0]
|
||||
|
||||
Pedestal_2filters_12keV:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/flat_2filters_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_2filters_pedestal_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
|
||||
# dark run: the model must find (almost) nothing here -- the hardest fake-rate test
|
||||
Pedestal_3filters_pos0_12keV:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_3filters_pos0_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2603_MaxIVBeamtime/2026032408/process/mtf/edge_3filters_pos0_pedestal_d0_f{}_0.raw
|
||||
signal_files: [0, 0]
|
||||
@@ -0,0 +1,80 @@
|
||||
# GridBased inference on measured data -- 15 keV Siemens star, MOENCH040 @150 V,
|
||||
# SOLEIL 2504 beamtime, with the polychromatic 2-20 keV model (2026-09-27/28)
|
||||
#
|
||||
# The star was recorded on the full 400x400 chip, 2000 files x 10 000 frames.
|
||||
# DataProcess/Configs.py analyses two regions of it:
|
||||
# SiemenStarLowerLeft x 130-240, y 110-220
|
||||
# SiemenStarLowerRight x 235-345, y 110-220
|
||||
# They share the same rows, so one crop covers both, extended by the halo R = 4
|
||||
# on every side: x 126-349, y 106-224. Its valid region is exactly x 130-345,
|
||||
# y 110-220; the notebook cuts the two regions out of it. The frames of each
|
||||
# file are read as that 118-row band only (RawFrameReader crop, ~3x faster than
|
||||
# whole frames on the NFS store), so both regions come out of one pass.
|
||||
#
|
||||
# The run is split into four parts of 500 files each so that a partial night
|
||||
# still leaves complete images; the notebook sums the parts it finds.
|
||||
|
||||
detector:
|
||||
n_x: 400
|
||||
n_y: 400
|
||||
corner: [0, 0] # full-chip frames on disk
|
||||
crop: [126, 349, 106, 224] # x0, x1, y0, y1 of the reconstructed window
|
||||
pixel_size_um: 25.0
|
||||
header_words: 56
|
||||
|
||||
calibration:
|
||||
file: /home/xie_x1/MLED/data-process/utils/BacksidePulsing_Calibration/Moench040/Moench040_AduToKevMapping_g4_50us_150V_250423.npy
|
||||
common_mode: column_masked # median over the uncharged pixels of the 118 rows. The
|
||||
# plain median (the 2026-09-27 run, tag _poly2to20) is pulled
|
||||
# up by the photons at ~5 % occupancy: 15 keV line at 14.47 keV
|
||||
pedestal_source: pedestal_run
|
||||
pedestal_frames: 2000 # of the 10 000 in the pedestal file
|
||||
|
||||
model:
|
||||
checkpoint: null # given on the command line (--checkpoint)
|
||||
threshold: 0.3
|
||||
merge_distance: 0.1
|
||||
|
||||
inference:
|
||||
n_frames: null
|
||||
precision: fp16
|
||||
batch_size: 512
|
||||
binning_factor: 10 # 2.5 um bins
|
||||
save_photons: false
|
||||
self_flattening: streaming # ~820 photons per frame here: the in-memory
|
||||
# remap would need ~100 GB per 5 M frames, so the
|
||||
# Rosenblatt table is built from the first 1e8
|
||||
# photons and every photon remapped as it comes
|
||||
# (src/flattening.py; identical to the in-memory
|
||||
# version when built from the same photons)
|
||||
flattening_lut_photons: 300000000 # buffered for the tables, ~2.4 GB
|
||||
# one table per local-occupancy class (photons / px / frame over the 9x9
|
||||
# receptive field): the sub-pixel phase depends on the flux, and one table for
|
||||
# the whole crop left a 25 um grid in the dim star of LowerLeft (4.4 % sub-pixel
|
||||
# rms at ~0.7 % occupancy -> 0.4 % with the classes; 600 k-frame test, 09-28)
|
||||
flattening_occupancy_edges: [0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07]
|
||||
energy_bins: [0.0, 30.0, 600] # 50 eV
|
||||
output_folder: /mnt/sls_det_storage/moench_data/MLXID/InferenceResults/GridBased
|
||||
|
||||
runs:
|
||||
SiemensStar_15keV_part0:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2504_SoleilBeamtime/Moench040_g4_SimonStars_150V_50us/15keV_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2504_SoleilBeamtime/Moench040_g4_SimonStars_150V_50us/15keV_signal_d0_f{}_0.raw
|
||||
signal_files: [0, 499]
|
||||
SiemensStar_15keV_part1:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2504_SoleilBeamtime/Moench040_g4_SimonStars_150V_50us/15keV_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2504_SoleilBeamtime/Moench040_g4_SimonStars_150V_50us/15keV_signal_d0_f{}_0.raw
|
||||
signal_files: [500, 999]
|
||||
SiemensStar_15keV_part2:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2504_SoleilBeamtime/Moench040_g4_SimonStars_150V_50us/15keV_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2504_SoleilBeamtime/Moench040_g4_SimonStars_150V_50us/15keV_signal_d0_f{}_0.raw
|
||||
signal_files: [1000, 1499]
|
||||
SiemensStar_15keV_part3:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2504_SoleilBeamtime/Moench040_g4_SimonStars_150V_50us/15keV_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2504_SoleilBeamtime/Moench040_g4_SimonStars_150V_50us/15keV_signal_d0_f{}_0.raw
|
||||
signal_files: [1500, 1999]
|
||||
# smoke test: one file, 10 000 frames
|
||||
SiemensStar_15keV_smoke:
|
||||
pedestal: /mnt/sls_det_storage/moench_data/2504_SoleilBeamtime/Moench040_g4_SimonStars_150V_50us/15keV_pedestal_d0_f0_0.raw
|
||||
signal_pattern: /mnt/sls_det_storage/moench_data/2504_SoleilBeamtime/Moench040_g4_SimonStars_150V_50us/15keV_signal_d0_f{}_0.raw
|
||||
signal_files: [1000, 1000]
|
||||
@@ -0,0 +1,49 @@
|
||||
# GridBased training -- 12 keV, MOENCH040 @150 V (WP3, monochromatic gate G2)
|
||||
|
||||
experiment:
|
||||
name: "12keV_Moench040"
|
||||
results_dir: "Results"
|
||||
|
||||
data:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/GridBased/12keV_Moench040_150V
|
||||
train_shards: [0, 11] # inclusive
|
||||
val_shards: [0, 1]
|
||||
max_train_frames: null # null = all
|
||||
max_val_frames: 8000
|
||||
input_scale: 12.0 # keV; frames are divided by this
|
||||
energy_scale: 12.0 # keV; energy target is E / energy_scale
|
||||
augment: true # 8-fold D4, a true symmetry of the problem
|
||||
batch_size_train: 256
|
||||
batch_size_val: 512
|
||||
num_workers: 8
|
||||
|
||||
model:
|
||||
channels: [32, 64, 64, 64] # 4 x conv3x3 -> receptive-field radius R = 4 px
|
||||
predict_energy: true
|
||||
norm: "none" # see models.py: 'group' breaks strict locality
|
||||
prior_prob: 0.01 # focal-loss bias init
|
||||
|
||||
loss:
|
||||
w_obj: 1.0
|
||||
w_off: 1.0
|
||||
w_ene: 0.1
|
||||
focal_alpha: 0.25
|
||||
focal_gamma: 2.0
|
||||
smooth_l1_beta_offset: 0.01 # px = 0.25 um, as for the cluster-based models
|
||||
smooth_l1_beta_energy: 0.02
|
||||
|
||||
training:
|
||||
epochs: 150
|
||||
lr: 1.0e-3
|
||||
weight_decay: 0.0
|
||||
scheduler_factor: 0.5
|
||||
scheduler_patience: 4
|
||||
amp: true
|
||||
seed: 0
|
||||
checkpoint_epochs: [25, 50, 75, 100, 125, 150]
|
||||
|
||||
eval:
|
||||
threshold: 0.3 # from the ROC of run 260830_00: eff plateaus below 0.3
|
||||
merge_distance: 0.1 # px; position-space duplicate suppression
|
||||
match_radius: 1.0 # px; 25 um
|
||||
pixel_size_um: 25.0
|
||||
@@ -0,0 +1,59 @@
|
||||
# GridBased training -- polychromatic 2-20 keV, MOENCH040 @150 V, [32, 64, 96, 96]
|
||||
#
|
||||
# The default poly architecture (Results/260919_poly3to30keV_Moench014_c96_00)
|
||||
# retrained for the 650 um MOENCH040 on flat 2-20 keV frames, to be tested on
|
||||
# the 12 keV MaxIV knife edge and the 15 keV SOLEIL Siemens star. Everything
|
||||
# but the data and the number of epochs is identical to the MOENCH014 c96.
|
||||
#
|
||||
# Same architecture and the same losses as the 12 keV configuration; what
|
||||
# changes is that the energy head now carries information, so it gets a real
|
||||
# weight and a scale that is not tied to a beam energy.
|
||||
|
||||
experiment:
|
||||
name: "poly2to20keV_Moench040_c96"
|
||||
results_dir: "Results"
|
||||
|
||||
data:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/GridBased/poly2to20keV_Moench040_150V
|
||||
train_shards: [0, 11]
|
||||
val_shards: [0, 1]
|
||||
max_train_frames: null
|
||||
max_val_frames: 8000
|
||||
input_scale: 15.0 # keV, mid-range; frames are divided by this
|
||||
energy_scale: 15.0 # keV, the energy target is E / energy_scale
|
||||
augment: true
|
||||
batch_size_train: 256
|
||||
batch_size_val: 512
|
||||
num_workers: 8
|
||||
|
||||
model:
|
||||
channels: [32, 64, 96, 96] # last two layers 96 wide: -35 % MAC, +23 % speed (FP16)
|
||||
predict_energy: true
|
||||
norm: "none"
|
||||
prior_prob: 0.01
|
||||
|
||||
loss:
|
||||
w_obj: 1.0
|
||||
w_off: 1.0
|
||||
w_ene: 1.0 # 0.1 at a single energy, where the head learned a
|
||||
# constant; here it carries the spectrum
|
||||
focal_alpha: 0.25
|
||||
focal_gamma: 2.0
|
||||
smooth_l1_beta_offset: 0.01
|
||||
smooth_l1_beta_energy: 0.03 # ~ the 0.39 keV noise floor of a 3x3 sum, / 15 keV
|
||||
|
||||
training:
|
||||
epochs: 200 # the 3-30 keV c96 run was within 0.004 % of its best val loss at 200
|
||||
lr: 1.0e-3
|
||||
weight_decay: 0.0
|
||||
scheduler_factor: 0.5
|
||||
scheduler_patience: 6
|
||||
amp: true
|
||||
seed: 0
|
||||
checkpoint_epochs: [50, 100, 150, 200]
|
||||
|
||||
eval:
|
||||
threshold: 0.3
|
||||
merge_distance: 0.1
|
||||
match_radius: 1.0
|
||||
pixel_size_um: 25.0
|
||||
@@ -0,0 +1,58 @@
|
||||
# GridBased training -- polychromatic 3-30 keV, MOENCH014 @150 V, variant c128
|
||||
#
|
||||
# One of four models trained on the same 3-30 keV frames to compare network
|
||||
# sizes (Results/overnight_poly3to30keV). Everything but model.channels is
|
||||
# identical to train_grid_poly_Moench014.yaml.
|
||||
#
|
||||
# Same architecture and the same losses as the 12 keV configuration; what
|
||||
# changes is that the energy head now carries information, so it gets a real
|
||||
# weight and a scale that is not tied to a beam energy.
|
||||
|
||||
experiment:
|
||||
name: "poly3to30keV_Moench014_c128"
|
||||
results_dir: "Results"
|
||||
|
||||
data:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/GridBased/poly3to30keV_Moench014_150V
|
||||
train_shards: [0, 11]
|
||||
val_shards: [0, 1]
|
||||
max_train_frames: null
|
||||
max_val_frames: 8000
|
||||
input_scale: 15.0 # keV, mid-range; frames are divided by this
|
||||
energy_scale: 15.0 # keV, the energy target is E / energy_scale
|
||||
augment: true
|
||||
batch_size_train: 256
|
||||
batch_size_val: 512
|
||||
num_workers: 8
|
||||
|
||||
model:
|
||||
channels: [32, 64, 128, 128] # reference width, as the 5-30 keV model
|
||||
predict_energy: true
|
||||
norm: "none"
|
||||
prior_prob: 0.01
|
||||
|
||||
loss:
|
||||
w_obj: 1.0
|
||||
w_off: 1.0
|
||||
w_ene: 1.0 # 0.1 at a single energy, where the head learned a
|
||||
# constant; here it carries the spectrum
|
||||
focal_alpha: 0.25
|
||||
focal_gamma: 2.0
|
||||
smooth_l1_beta_offset: 0.01
|
||||
smooth_l1_beta_energy: 0.03 # ~ the 0.39 keV noise floor of a 3x3 sum, / 15 keV
|
||||
|
||||
training:
|
||||
epochs: 300
|
||||
lr: 1.0e-3
|
||||
weight_decay: 0.0
|
||||
scheduler_factor: 0.5
|
||||
scheduler_patience: 6
|
||||
amp: true
|
||||
seed: 0
|
||||
checkpoint_epochs: [50, 100, 150, 200, 250, 300]
|
||||
|
||||
eval:
|
||||
threshold: 0.3
|
||||
merge_distance: 0.1
|
||||
match_radius: 1.0
|
||||
pixel_size_um: 25.0
|
||||
@@ -0,0 +1,58 @@
|
||||
# GridBased training -- polychromatic 3-30 keV, MOENCH014 @150 V, variant c64
|
||||
#
|
||||
# One of four models trained on the same 3-30 keV frames to compare network
|
||||
# sizes (Results/overnight_poly3to30keV). Everything but model.channels is
|
||||
# identical to train_grid_poly_Moench014.yaml.
|
||||
#
|
||||
# Same architecture and the same losses as the 12 keV configuration; what
|
||||
# changes is that the energy head now carries information, so it gets a real
|
||||
# weight and a scale that is not tied to a beam energy.
|
||||
|
||||
experiment:
|
||||
name: "poly3to30keV_Moench014_c64"
|
||||
results_dir: "Results"
|
||||
|
||||
data:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/GridBased/poly3to30keV_Moench014_150V
|
||||
train_shards: [0, 11]
|
||||
val_shards: [0, 1]
|
||||
max_train_frames: null
|
||||
max_val_frames: 8000
|
||||
input_scale: 15.0 # keV, mid-range; frames are divided by this
|
||||
energy_scale: 15.0 # keV, the energy target is E / energy_scale
|
||||
augment: true
|
||||
batch_size_train: 256
|
||||
batch_size_val: 512
|
||||
num_workers: 8
|
||||
|
||||
model:
|
||||
channels: [32, 64, 64, 64] # the 12 keV model size: -61 % MAC, +83 % speed (FP16)
|
||||
predict_energy: true
|
||||
norm: "none"
|
||||
prior_prob: 0.01
|
||||
|
||||
loss:
|
||||
w_obj: 1.0
|
||||
w_off: 1.0
|
||||
w_ene: 1.0 # 0.1 at a single energy, where the head learned a
|
||||
# constant; here it carries the spectrum
|
||||
focal_alpha: 0.25
|
||||
focal_gamma: 2.0
|
||||
smooth_l1_beta_offset: 0.01
|
||||
smooth_l1_beta_energy: 0.03 # ~ the 0.39 keV noise floor of a 3x3 sum, / 15 keV
|
||||
|
||||
training:
|
||||
epochs: 300
|
||||
lr: 1.0e-3
|
||||
weight_decay: 0.0
|
||||
scheduler_factor: 0.5
|
||||
scheduler_patience: 6
|
||||
amp: true
|
||||
seed: 0
|
||||
checkpoint_epochs: [50, 100, 150, 200, 250, 300]
|
||||
|
||||
eval:
|
||||
threshold: 0.3
|
||||
merge_distance: 0.1
|
||||
match_radius: 1.0
|
||||
pixel_size_um: 25.0
|
||||
@@ -0,0 +1,58 @@
|
||||
# GridBased training -- polychromatic 3-30 keV, MOENCH014 @150 V, variant c96
|
||||
#
|
||||
# One of four models trained on the same 3-30 keV frames to compare network
|
||||
# sizes (Results/overnight_poly3to30keV). Everything but model.channels is
|
||||
# identical to train_grid_poly_Moench014.yaml.
|
||||
#
|
||||
# Same architecture and the same losses as the 12 keV configuration; what
|
||||
# changes is that the energy head now carries information, so it gets a real
|
||||
# weight and a scale that is not tied to a beam energy.
|
||||
|
||||
experiment:
|
||||
name: "poly3to30keV_Moench014_c96"
|
||||
results_dir: "Results"
|
||||
|
||||
data:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/GridBased/poly3to30keV_Moench014_150V
|
||||
train_shards: [0, 11]
|
||||
val_shards: [0, 1]
|
||||
max_train_frames: null
|
||||
max_val_frames: 8000
|
||||
input_scale: 15.0 # keV, mid-range; frames are divided by this
|
||||
energy_scale: 15.0 # keV, the energy target is E / energy_scale
|
||||
augment: true
|
||||
batch_size_train: 256
|
||||
batch_size_val: 512
|
||||
num_workers: 8
|
||||
|
||||
model:
|
||||
channels: [32, 64, 96, 96] # last two layers 96 wide: -35 % MAC, +23 % speed (FP16)
|
||||
predict_energy: true
|
||||
norm: "none"
|
||||
prior_prob: 0.01
|
||||
|
||||
loss:
|
||||
w_obj: 1.0
|
||||
w_off: 1.0
|
||||
w_ene: 1.0 # 0.1 at a single energy, where the head learned a
|
||||
# constant; here it carries the spectrum
|
||||
focal_alpha: 0.25
|
||||
focal_gamma: 2.0
|
||||
smooth_l1_beta_offset: 0.01
|
||||
smooth_l1_beta_energy: 0.03 # ~ the 0.39 keV noise floor of a 3x3 sum, / 15 keV
|
||||
|
||||
training:
|
||||
epochs: 300
|
||||
lr: 1.0e-3
|
||||
weight_decay: 0.0
|
||||
scheduler_factor: 0.5
|
||||
scheduler_patience: 6
|
||||
amp: true
|
||||
seed: 0
|
||||
checkpoint_epochs: [50, 100, 150, 200, 250, 300]
|
||||
|
||||
eval:
|
||||
threshold: 0.3
|
||||
merge_distance: 0.1
|
||||
match_radius: 1.0
|
||||
pixel_size_um: 25.0
|
||||
@@ -0,0 +1,58 @@
|
||||
# GridBased training -- polychromatic 3-30 keV, MOENCH014 @150 V, variant r3
|
||||
#
|
||||
# One of four models trained on the same 3-30 keV frames to compare network
|
||||
# sizes (Results/overnight_poly3to30keV). Everything but model.channels is
|
||||
# identical to train_grid_poly_Moench014.yaml.
|
||||
#
|
||||
# Same architecture and the same losses as the 12 keV configuration; what
|
||||
# changes is that the energy head now carries information, so it gets a real
|
||||
# weight and a scale that is not tied to a beam energy.
|
||||
|
||||
experiment:
|
||||
name: "poly3to30keV_Moench014_r3"
|
||||
results_dir: "Results"
|
||||
|
||||
data:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/GridBased/poly3to30keV_Moench014_150V
|
||||
train_shards: [0, 11]
|
||||
val_shards: [0, 1]
|
||||
max_train_frames: null
|
||||
max_val_frames: 8000
|
||||
input_scale: 15.0 # keV, mid-range; frames are divided by this
|
||||
energy_scale: 15.0 # keV, the energy target is E / energy_scale
|
||||
augment: true
|
||||
batch_size_train: 256
|
||||
batch_size_val: 512
|
||||
num_workers: 8
|
||||
|
||||
model:
|
||||
channels: [32, 64, 128] # 3 layers, R = 3 px (7x7 field): -61 % MAC, +78 % speed (FP16)
|
||||
predict_energy: true
|
||||
norm: "none"
|
||||
prior_prob: 0.01
|
||||
|
||||
loss:
|
||||
w_obj: 1.0
|
||||
w_off: 1.0
|
||||
w_ene: 1.0 # 0.1 at a single energy, where the head learned a
|
||||
# constant; here it carries the spectrum
|
||||
focal_alpha: 0.25
|
||||
focal_gamma: 2.0
|
||||
smooth_l1_beta_offset: 0.01
|
||||
smooth_l1_beta_energy: 0.03 # ~ the 0.39 keV noise floor of a 3x3 sum, / 15 keV
|
||||
|
||||
training:
|
||||
epochs: 300
|
||||
lr: 1.0e-3
|
||||
weight_decay: 0.0
|
||||
scheduler_factor: 0.5
|
||||
scheduler_patience: 6
|
||||
amp: true
|
||||
seed: 0
|
||||
checkpoint_epochs: [50, 100, 150, 200, 250, 300]
|
||||
|
||||
eval:
|
||||
threshold: 0.3
|
||||
merge_distance: 0.1
|
||||
match_radius: 1.0
|
||||
pixel_size_um: 25.0
|
||||
@@ -0,0 +1,56 @@
|
||||
# GridBased training -- polychromatic 5-30 keV, MOENCH014 @150 V
|
||||
#
|
||||
# Same architecture and the same losses as the 12 keV configuration; what
|
||||
# changes is that the energy head now carries information, so it gets a real
|
||||
# weight and a scale that is not tied to a beam energy.
|
||||
|
||||
experiment:
|
||||
name: "poly5to30keV_Moench014"
|
||||
results_dir: "Results"
|
||||
|
||||
data:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/GridBased/poly5to30keV_Moench014_150V
|
||||
train_shards: [0, 11]
|
||||
val_shards: [0, 1]
|
||||
max_train_frames: null
|
||||
max_val_frames: 8000
|
||||
input_scale: 15.0 # keV, mid-range; frames are divided by this
|
||||
energy_scale: 15.0 # keV, the energy target is E / energy_scale
|
||||
augment: true
|
||||
batch_size_train: 256
|
||||
batch_size_val: 512
|
||||
num_workers: 8
|
||||
|
||||
model:
|
||||
channels: [32, 64, 128, 128] # still 4 x conv3x3, so R = 4 px; wider, because
|
||||
# the cloud size now has to be disentangled from
|
||||
# the energy rather than mapping straight to depth
|
||||
predict_energy: true
|
||||
norm: "none"
|
||||
prior_prob: 0.01
|
||||
|
||||
loss:
|
||||
w_obj: 1.0
|
||||
w_off: 1.0
|
||||
w_ene: 1.0 # 0.1 at a single energy, where the head learned a
|
||||
# constant; here it carries the spectrum
|
||||
focal_alpha: 0.25
|
||||
focal_gamma: 2.0
|
||||
smooth_l1_beta_offset: 0.01
|
||||
smooth_l1_beta_energy: 0.03 # ~ the 0.39 keV noise floor of a 3x3 sum, / 15 keV
|
||||
|
||||
training:
|
||||
epochs: 300
|
||||
lr: 1.0e-3
|
||||
weight_decay: 0.0
|
||||
scheduler_factor: 0.5
|
||||
scheduler_patience: 6
|
||||
amp: true
|
||||
seed: 0
|
||||
checkpoint_epochs: [50, 100, 150, 200, 250, 300]
|
||||
|
||||
eval:
|
||||
threshold: 0.3
|
||||
merge_distance: 0.1
|
||||
match_radius: 1.0
|
||||
pixel_size_um: 25.0
|
||||
@@ -0,0 +1,549 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d50894bb",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Knife edge, 0 filter — GridBased against eta interpolation\n",
|
||||
"\n",
|
||||
"The highest flux point of the scan: **10.8 % occupancy** (flat field, inside\n",
|
||||
"the ESF ROI), 14.4x the 3-filter point and above where the cluster chain was ever\n",
|
||||
"operated.\n",
|
||||
"\n",
|
||||
"No cluster-based reconstruction exists at this flux point: the beamtime\n",
|
||||
"only wrote cluster files for the 1-, 2- and 3-filter measurements\n",
|
||||
"(`Samples/Measurement/2603MaxIV_*Filters_12keV`), so neither the CNN\n",
|
||||
"chain nor eta interpolation has a 0-filter image. Only the GridBased reconstruction\n",
|
||||
"is analysed here; the classical chains are compared against GridBased in the other three notebooks.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**Edge width (revised 2026-09-28).** The ESF is binned and fitted exactly as\n",
|
||||
"`Plotting/fig_knife_edge.py --fit odr` does it: `generate_presampled_esf()` and\n",
|
||||
"`get_odr_fitting()` from `DeepLearning/src/funcs_postprocess.py` (bin content\n",
|
||||
"Σk/Σf), symmetric ±4σ window, **ESF bin width 0.3 µm**. The ODR model is\n",
|
||||
"`p0/2 (1 + erf((x - p1)/(sqrt(2) sigma))) + p3`, so the fit gives **sigma**, the\n",
|
||||
"width of the Gaussian LSF, which is what the tables quote, with\n",
|
||||
"`MTF50 [lp/mm] = 1000 sqrt(ln 2 / 2) / (pi sigma)`; MTF50 and MTF(200 lp/mm) are\n",
|
||||
"also measured from the LSF (`Plotting/knife_edge_numbers.py`: first crossing,\n",
|
||||
"central-difference correction), and the relative DQE uses the latter. Only the\n",
|
||||
"flattened GridBased reconstruction is analysed. Same processing as\n",
|
||||
"`KnifeEdge_poly2to20keV_Moench040.ipynb`.\n",
|
||||
"\n",
|
||||
"**Occupancy** is that of the flat field inside the ESF ROI: the reconstructed\n",
|
||||
"photons per 25 µm pixel per frame over `ROI // 10` (x 33–46, y 26–49 of the\n",
|
||||
"99 × 99 frame), the pixels over which `DeepLearning/Notebooks/KnifeEdge_3filters_pos0.ipynb`\n",
|
||||
"sums the deposited energy (0.705 % at 3 filters from the energy, 0.747 % here\n",
|
||||
"from the photons of the 12 keV model).\n",
|
||||
"\n",
|
||||
"*Until 2026-09-28 this notebook took the fitted sigma for sqrt(2) sigma (so its\n",
|
||||
"MTF50 was sqrt(2) too high), used 0.5 µm bins, and binned the ESF with an older\n",
|
||||
"copy of `generate_presampled_esf` (inverse-variance mean of k/f, biased low in\n",
|
||||
"the toe, sigma ~3 % too small). The previous version is in\n",
|
||||
"`Backup_260928_pre_sigma_fix/`.*\n",
|
||||
"\n",
|
||||
"The ROI, the oversampled ESF and the erf fit are the ones from\n",
|
||||
"`DeepLearning/Notebooks/KnifeEdge_3filters_pos0.ipynb`; the edge sits at the\n",
|
||||
"same place at all three flux points, so the same ROI holds throughout and the\n",
|
||||
"three notebooks are directly comparable.\n",
|
||||
"\n",
|
||||
"Run in the `pytorch_nightly` environment (ROOT + scipy + jupyter)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "3975e8f9",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:08.904496Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:08.904413Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:10.494059Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:10.493725Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Welcome to JupyROOT 6.28/10\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import json\n",
|
||||
"import sys\n",
|
||||
"from pathlib import Path\n",
|
||||
"\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"REPO = Path('/home/xie_x1/MLXID/GridBased')\n",
|
||||
"sys.path.insert(0, '/home/xie_x1/MLXID/DeepLearning/src') # the code Plotting/ uses\n",
|
||||
"sys.path.insert(0, '/home/xie_x1/MLXID/Plotting')\n",
|
||||
"from ROOT import TCanvas, gROOT\n",
|
||||
"gROOT.SetBatch(True)\n",
|
||||
"from funcs_postprocess import generate_presampled_esf, get_odr_fitting\n",
|
||||
"from knife_edge_numbers import mtf as mtf_from_lsf # first crossing, sinc-corrected\n",
|
||||
"\n",
|
||||
"GRID = Path('/mnt/sls_det_storage/moench_data/MLXID/InferenceResults/GridBased')\n",
|
||||
"PUBLISHED = Path('/home/xie_x1/MLXID/DeepLearning/InferenceResults')\n",
|
||||
"ETA = Path('/home/xie_x1/MLXID/EtaInterpolation/Results')\n",
|
||||
"\n",
|
||||
"EDGE_RUN, FLAT_RUN = 'Edge_0filters_12keV', 'Flat_0filters_12keV'\n",
|
||||
"BIN_UM = 2.5 # super-pixel = 25 um / 10\n",
|
||||
"ROI = (330, 465, 260, 490) # x1, x2, y1, y2, as published\n",
|
||||
"CROP = slice(10, -10) # 1010 -> 990, as published\n",
|
||||
"BIN_WIDTH_UM = 0.3 # presampled ESF bin, as Plotting/ and the manuscript\n",
|
||||
"\n",
|
||||
"plt.rcParams.update({'figure.dpi': 110, 'image.cmap': 'gray',\n",
|
||||
" 'image.origin': 'lower', 'image.interpolation': 'nearest'})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8c496448",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1. Load every reconstruction of the same measurement"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "4bcf2cfb",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:10.495691Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:10.495537Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:10.618415Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:10.618180Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"GridBased model epoch 135, 3,500,000 frames, occupancy 10.770 % (flat field, ESF ROI)\n",
|
||||
" sub-pixel excess rms 18.3 % -> 1.6 % after flattening\n",
|
||||
"\n",
|
||||
"variant edge photons flat photons relative\n",
|
||||
"GridBased flat 6.8684e+08 1.1910e+09 1.000\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def crop(image):\n",
|
||||
" \"\"\"The published frames are cropped by 10 super-pixels on each side.\"\"\"\n",
|
||||
" return image[CROP, CROP] if image.shape[0] == 1010 else image\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"for run in (EDGE_RUN, FLAT_RUN):\n",
|
||||
" if not (GRID / run / 'summary.json').exists():\n",
|
||||
" raise SystemExit(\n",
|
||||
" f'{run} has not been reconstructed yet. Run:\\n'\n",
|
||||
" f' python scripts/05_infer_measurement.py '\n",
|
||||
" f'--config Configs/infer_measurement_12keV.yaml --run {run}')\n",
|
||||
"\n",
|
||||
"grid_summary = json.load(open(GRID / EDGE_RUN / 'summary.json'))\n",
|
||||
"flat_summary = json.load(open(GRID / FLAT_RUN / 'summary.json'))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def grid_image(run, flattened):\n",
|
||||
" name = 'binned_image_flattened.npy' if flattened else 'binned_image.npy'\n",
|
||||
" return np.load(GRID / run / name).astype(float)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"variants = {\n",
|
||||
" 'GridBased flat': (grid_image(EDGE_RUN, True), grid_image(FLAT_RUN, True)),\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"# This flux point was never clustered: only 2603MaxIV_{Edge,Flat}{1,2,3}Filters\n",
|
||||
"# exist under Samples/Measurement, so there is no CNN and no eta image to load\n",
|
||||
"# here. (Until 2026-09-17 this cell loaded the *1-filter* eta image, which is a\n",
|
||||
"# different measurement at 2.4x the flux and was not comparable with anything.)\n",
|
||||
"\n",
|
||||
"ORDER = ['GridBased flat']\n",
|
||||
"variants = {name: (crop(e), crop(f)) for name, (e, f) in variants.items()}\n",
|
||||
"variants = {name: variants[name] for name in ORDER}\n",
|
||||
"\n",
|
||||
"def flat_occupancy(run):\n",
|
||||
" # reconstructed photons per 25 um pixel per frame in the flat field, inside the\n",
|
||||
" # ESF ROI: ROI // 10 in pixels of the 99 x 99 frame, both ends included as in\n",
|
||||
" # DeepLearning/Notebooks; +1 because the 101 x 101 frame is cropped by 1 px\n",
|
||||
" summary = json.load(open(GRID / run / 'summary.json'))\n",
|
||||
" native = np.load(GRID / run / 'native_image.npy') / summary['n_frames']\n",
|
||||
" x0, x1, y0, y1 = (v // 10 for v in ROI)\n",
|
||||
" return float(native[y0 + 1:y1 + 2, x0 + 1:x1 + 2].mean())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"occupancy = flat_occupancy(FLAT_RUN)\n",
|
||||
"print(f\"GridBased model epoch {grid_summary['epoch']}, \"\n",
|
||||
" f\"{grid_summary['n_frames']:,} frames, \"\n",
|
||||
" f\"occupancy {occupancy*100:.3f} % (flat field, ESF ROI)\")\n",
|
||||
"print(f\" sub-pixel excess rms {grid_summary['subpixel_nonuniformity_before']*100:.1f} % -> \"\n",
|
||||
" f\"{grid_summary['subpixel_nonuniformity_after']*100:.1f} % after flattening\\n\")\n",
|
||||
"print(f\"{'variant':16s} {'edge photons':>14} {'flat photons':>14} relative\")\n",
|
||||
"reference = variants['GridBased flat'][0].sum()\n",
|
||||
"for name, (e, f) in variants.items():\n",
|
||||
" print(f'{name:16s} {e.sum():14.4e} {f.sum():14.4e} {e.sum()/reference:8.3f}')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "21d95658",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:10.619670Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:10.619469Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:10.852109Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:10.851858Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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1tZWzJkzB6NHj8brr7+OSZMmYcCAAR3G/t///V+cddZZ2HXXXXHFFVfA5/PhwQcfrJkrffLJJ+Pee+/FtGnTcOKJJwIA/vCHP+Doo4/G7bffjjlz5nT+IKqw/fbbY9ddd8WLL75oe/1Pf/oT3G531dd33313DB48uOp4BxxwAG666Sacf/75OProo00IbzQatR33zjvvYPLkyfjBD36AGTNm4O9//zsWLFiAlpYWPPvss53O+ac//SkaGxvxxBNP4KabbsLAgQMB2MOLAWDevHlIJBI4+eSTEY1Gce+99+KCCy7AkCFDcMIJJ5jjeuNzAgDpdBoHHnggxo0bh6uuugorV67E//7v/+Lb3/42Xn/9dey+++5djtEZhx9+OOLxOC699FI0Nzfj17/+NQ4//HA888wzOPTQQ3s01vr163HQQQehUqng9NNPxw477ICWlha89957+POf/4yTTz7Zdvwdd9yB1atX47TTTsOgQYPwhz/8AT/72c8Qi8VsYdN9+e+lMyqVSlVxDwD19fXm+Y0aNQr/+te/sGDBApx77rndLmRXbey6uroOKTDdpVAoYOXKlSYHnCxatAjZbBbf//73EYlEqp7rdrsxe/ZsnH766Xj88cex2267bdQcFEVRFEVRlK8gVg+56667LADWyy+/bOVyOeuEE06w3G639atf/arDsSNGjLAAWA888IDt9WuuucYCYD333HPmtZdfftkCYN11110dxjjwwANtr2WzWWvbbbe1JkyYYOVyOdt7jz76qAXAuvvuu7u8lz322MPaYYcdrPXr19te/9vf/ma53W5r/vz55rXvf//7FgDriSeeqHovI0aMMK+1tLRYkUjE2nHHHa1EImFez+Vy1t57720BsC6//HLz+sKFCy0A1o033thhjt/97neteDxuG6cnnHnmmZbL5bLWrl1rWZZlffrppxYAcz+ffPKJZVmW9cUXX1gul8s699xzzbnVngnPl/OXALBcLpf12muv2V4//fTTLQDWv/71ry7nfPnll1sArE8//bTDe/z8jR071vbsU6mUNWDAAGu//fYzr/XW5+TAAw+0AFhnnnmm7fU33njDcrlc1iGHHGJeq/U5rnVfJ510kgXAOvLII61yuWxe/+yzz6xwOGztvPPOVqVSMa9X+/dw4IEH2j5/f/zjHy0A1kMPPdTpfXGu2267rdXc3GxeL5fL1ujRo60hQ4bYju+rfy+dwf+G1Pp69dVXbfPw+/0WAGv48OHWD37wA+uWW26x/vGPf1Qdm8+12tczzzzT5dz4PJ9++mnryy+/tNauXWstWbLEOvrooy0A1gknnGA7/sILL7QAWI8//nin47755psWAOvYY4/tcC15v4qiKIqiKMrWxUaHnbe0tOCwww7DwoUL8eijj+Kcc86petx2222HmTNn2l77zne+A6A9TLSnvPjii/j8888xa9YsJJNJrFu3znwdeOCBiEQieO655zod4/3338c//vEPnHDCCcZZ49eoUaOw8847mzEqlQoWLlyIMWPGYPr06bZxzjvvvA7O7/PPP490Oo0zzjjDVrgpEAjg/PPP7zCX++67D6FQCDNmzLDNY926dTj66KORSCTw+uuvb9RaHXLIIbAsy4Qw/+lPf4LH48EVV1wBj8eDP/3pTwCAl156CZZl1QzZ7Qn77bcfvvWtb9le29Rn7uSss86yhe1GIhHst99+tvF743MimTdvnu33CRMm4NBDD8VLL72ElpaWTbqfn/zkJ7YokBEjRuDEE0/Ehx9+iHfffbdHY9FtXbx4Mdra2ro8/pRTTkFDQ4P53e1245BDDsGaNWuQSqUA9O2/l67Ybrvt8MILL1T9ampqMsfts88+eOutt3DqqaeiVCrh3nvvxdlnn4099tgD48eP75AiwHutNu7ee+/d7fl997vfxaBBgzB48GBMmDABTz75JP7f//t/HXK2+SwYHVALvt+dZ6coiqIoiqJsPWx02PmsWbOQSCTwwgsvdBoWu+OOO3Z4jWGn69ev36hrL1u2DABwxhln4Iwzzqh6DPOWuxrjmmuuwTXXXFP1GM79iy++QDKZxJgxYzocEwwGMWrUKFtbrE8++QQAsOuuu3Y4fvTo0VXnks1msf3229ecb1f3U4uDDjrIhJifcMIJePHFF7Hnnntihx12wPjx4/Hiiy/itNNOw4svvgiPx4MDDzxwo64j6Ytn3t1ryPF743NC6uvrsd1223V4fcyYMXjhhRfwySefYM899+zWWNWo9tniax999BG++c1vdnusAw44AKeccgp+97vf4cEHH8See+6JiRMn4rjjjsN+++3X4fiunlc0Gu3Tfy9dEQqFuh16v9tuu2HBggUAgFWrVuEvf/kL7r33XixevBhTpkzBBx98YNtocLlcPQ7rd3LTTTdh9913Rzabxeuvv47rr78en3/+eYew9Xg8DqBrUd1dka4oiqIoiqJsXWy0+J4xYwZ+97vf4corr8Q+++xTszWPrPTrxNrI9kiVSgUAcPXVV2PChAlVj5F/YHc2xtlnn42jjjqq6jHdbfVT6z66m3NaqVRQV1eHxx57rOYxG5v7WV9Line truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1650x506 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"fig, axes = plt.subplots(1, len(ORDER) if len(ORDER) < 4 else 3, figsize=(15, 4.6))\n",
|
||||
"extent = [0, 990 * BIN_UM, 0, 990 * BIN_UM]\n",
|
||||
"shown = ORDER if len(ORDER) < 4 else ['eta', 'cluster <=3ph', 'GridBased flat']\n",
|
||||
"for ax, name in zip(np.atleast_1d(axes), shown):\n",
|
||||
" image = variants[name][0]\n",
|
||||
" im = ax.imshow(image, extent=extent, vmax=np.percentile(image, 99.5))\n",
|
||||
" ax.add_patch(plt.Rectangle((ROI[0]*BIN_UM, ROI[2]*BIN_UM),\n",
|
||||
" (ROI[1]-ROI[0])*BIN_UM, (ROI[3]-ROI[2])*BIN_UM,\n",
|
||||
" edgecolor='red', facecolor='none', lw=1.4))\n",
|
||||
" ax.set_title(name); ax.set_xlabel('x [um]'); ax.set_ylabel('y [um]')\n",
|
||||
" plt.colorbar(im, ax=ax, fraction=0.046)\n",
|
||||
"fig.suptitle('knife edge, with the published ESF ROI')\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "782d9a37",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2. Edge spread function\n",
|
||||
"\n",
|
||||
"`generate_presampled_esf` fits an erf to every row of the ROI, fits a straight\n",
|
||||
"line through the edge positions, and re-samples the ROI onto a common axis;\n",
|
||||
"`get_odr_fitting` then fits the erf with x and y errors inside |x - p1| <= 4 sigma\n",
|
||||
"(the fit of `Plotting/fig_knife_edge.py --fit odr`)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "7a741198",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:10.853265Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:10.853179Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:11.402245Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:11.401964Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Final Edge Midpoint Fit: slope = -0.0858, intercept = 433.2022, chi2/ndf = 0.0302\n",
|
||||
"variant sigma [um] chi2/ndf MTF50 MTF50 LSF MTF(200) LSF rows\n",
|
||||
"GridBased flat 1.473 +- 0.017 1.30 127.2 133.0 0.222 100%\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def analyse(edge_image, flat_image, label):\n",
|
||||
" esf = generate_presampled_esf(edge_image, flat_image, ROI,\n",
|
||||
" pixel_size_um=BIN_UM, bin_width_um=BIN_WIDTH_UM,\n",
|
||||
" chi2_threshold=15.0, residual_tolerance_px=1.0)\n",
|
||||
" x, z = esf['numpy']['x'], esf['numpy']['z']\n",
|
||||
" odr = get_odr_fitting(x, z, esf['numpy']['x_err'], esf['numpy']['z_err'], n_sigma=4.0)\n",
|
||||
" sigma, sigma_err = odr['sigma_um'], odr['sigma_err_um'] # sigma of the Gaussian LSF\n",
|
||||
" try:\n",
|
||||
" mtf50_lsf, mtf200_lsf = mtf_from_lsf(dict(x=x, z=z, pars=odr['beta']))\n",
|
||||
" except Exception:\n",
|
||||
" mtf50_lsf = mtf200_lsf = np.nan\n",
|
||||
" n_fit = int(odr['mask'].sum())\n",
|
||||
" ndf = max(n_fit - len(odr['beta']), 1)\n",
|
||||
" x_fit = x[odr['mask']]\n",
|
||||
" return dict(label=label, x=x, z=z, sigma=sigma, sigma_err=sigma_err, sigma_gauss=sigma,\n",
|
||||
" chi2_ndf=odr['chi2_ndf'], chi2=odr['chi2_ndf'] * ndf, ndf=ndf,\n",
|
||||
" mtf50=1000 * np.sqrt(np.log(2) / 2) / (np.pi * sigma),\n",
|
||||
" mtf10=1000 * np.sqrt(np.log(10) / 2) / (np.pi * sigma),\n",
|
||||
" mtf50_lsf=mtf50_lsf, mtf200_lsf=mtf200_lsf,\n",
|
||||
" rows_kept=esf['valid_lines_ratio'],\n",
|
||||
" edge_slope=esf['edge_slope'], edge_centre=odr['beta'][1],\n",
|
||||
" fit_points=n_fit, fit_range=(x_fit.min(), x_fit.max()),\n",
|
||||
" photons=float(edge_image.sum()), odr=odr)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"results = {name: analyse(edge, flat, name) for name, (edge, flat) in variants.items()}\n",
|
||||
"\n",
|
||||
"print(f\"{'variant':16s} {'sigma [um]':>16} {'chi2/ndf':>9} {'MTF50':>7} {'MTF50 LSF':>9} \"\n",
|
||||
" f\"{'MTF(200) LSF':>12} {'rows':>6}\")\n",
|
||||
"for name, r in results.items():\n",
|
||||
" print(f\"{name:16s} {r['sigma']:7.3f} +- {r['sigma_err']:.3f} {r['chi2_ndf']:9.2f} {r['mtf50']:7.1f} \"\n",
|
||||
" f\"{r['mtf50_lsf']:9.1f} {r['mtf200_lsf']:12.3f} {r['rows_kept']*100:5.0f}%\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "f14649cd",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:11.403441Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:11.403279Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:11.709352Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:11.709131Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1375x528 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"COLOURS = {'eta': '#a0451c', 'cluster 1ph': '#6b6b6b', 'cluster <=2ph': '#7b5aa6',\n",
|
||||
" 'cluster <=3ph': '#4b2a6b', 'GridBased raw': '#4cbcac',\n",
|
||||
" 'GridBased flat': '#10695f'}\n",
|
||||
"frequency = np.linspace(0, 400, 2000)\n",
|
||||
"fig, ax = plt.subplots(1, 2, figsize=(12.5, 4.8))\n",
|
||||
"for name, r in results.items():\n",
|
||||
" ax[0].plot(r['x'], r['z'], lw=1.1, color=COLOURS[name],\n",
|
||||
" label=f\"{name}: $\\\\sigma$ = {r['sigma']:.3f} $\\\\pm$ {r['sigma_err']:.3f} $\\\\mu$m\")\n",
|
||||
" sigma_mm = r['sigma_gauss'] / 1000.0\n",
|
||||
" ax[1].plot(frequency, np.exp(-2 * np.pi**2 * sigma_mm**2 * frequency**2),\n",
|
||||
" lw=1.6, color=COLOURS[name], label=f\"{name} ({r['mtf50']:.0f} lp/mm)\")\n",
|
||||
"ax[0].set_xlim(-9, 9); ax[0].set_ylim(-0.05, 1.35)\n",
|
||||
"ax[0].set_xlabel(r'position across the edge [$\\mu$m]')\n",
|
||||
"ax[0].set_ylabel('relative intensity')\n",
|
||||
"ax[0].legend(fontsize=8); ax[0].grid(alpha=.3); ax[0].set_title('oversampled ESF')\n",
|
||||
"ax[1].axvline(200, color='k', ls=':', lw=.8, label='2.5 um Nyquist')\n",
|
||||
"ax[1].axhline(0.5, color='grey', lw=.5)\n",
|
||||
"ax[1].set_xlim(0, 400); ax[1].set_ylim(0, 1.05)\n",
|
||||
"ax[1].set_xlabel('spatial frequency [lp/mm]'); ax[1].set_ylabel('MTF')\n",
|
||||
"ax[1].legend(fontsize=8); ax[1].grid(alpha=.3); ax[1].set_title('MTF from the fitted ESF')\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "f81b1689",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3. Where the GridBased sub-pixel phase stands"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "be944928",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:11.710528Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:11.710438Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:12.378356Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:12.378123Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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bTjnnHPwwQ9+EFdddRU2bdqESy+9FKOjo/j5z3+Oo446Cg888ADe9KY34bzzzsOHP/xhVUef+9zncN111+Gyyy7D6173Ovzxj3/EZz7zGRSLRVx++eXKjnq9jvPPPx+f+cxncPXVV6O9vR2rVq3C8ccfjyVLluDHP/4xTNPEV77yFZx00kl47rnnkEwmJ5VHQoacf/75WLhwIS6//PItngcAQ0ND6OjowLXXXov29nasWLECV155Jfr7+/GjH/0IAPDAAw/gNa95DT796U/jvPPOA0AskK0dB4C///u/xw9/+EN88YtfxLHHHov7778fn//855FOp3HRRRfF6v69730vLr74Ylx++eW4+uqr8c53vhNr165FZ2fnS7bZttJdeuml+P73v48vf/nLOOKII3DLLbfgn//5n7evU2hoaGho7LfQc5ztw4YNG3DwwQfj/PPPRz6fxxNPPIErrrgCpVIJX/rSl7Y6X6jVarv8fN/SnKYZLzV32pmy/PKXv8Tf/d3f4atf/apir7zUcQB497vfjXvvvRdXXHEFFi1ahDvvvBPvfe970d7ejlNPPVVdv7+/HxdffDEuvfRStLS04NJLL8VZZ52FF154AY7jbLUNtifdBz/4Qfz5z3/G17/+dcyaNQvf//738fjjj293O2toaGhoaGhoaGi8LBFqaOxB3HrrrSGAcPXq1erY6tWrQwDhrbfeusU0vu+HruuGBx98cPiFL3xBHb/iiivCbDa72647Pj4e5nK52DXCMAyvv/76MJ1Oh0NDQ2EYhuHdd98dAggfeeSRMAzDcOnSpaFhGOF//dd/qTSu64YzZ84Md2ZIXXHFFSGAWH6e54WzZ88Ozz333DAMwzAIgnDWrFnqu+COO+4IDcMIn3nmGXUsm82GV1xxhfo+ODgYOo4Tfu5zn4ul/ehHPxpms9mwWCzG7Ljlllti511wwQXhnDlzwkqloo4NDAyE2Ww2vP7661+ybIccckj4/ve/P3bs/e9/f3jIIYdsNY3ruuFPf/rT0LbtsFQqqeMAwn/7t3+bdP6Wjj///POhYRjh97///djxz33uc+GUKVNC3/djZb7jjjvUOStXrgwBhD/5yU/UsRNPPDE87bTT1PftSTc8PBymUqnwy1/+csyGE088cVLf1NDQ0NA48KDnODuGIAhC13XDr3zlK2FfX1/sty3NF3bH8715TrM1NM+dwnDys397yrK19t/a8T//+c8hgPAPf/hD7PjZZ58dHn300er7+9///knzvT/+8Y8hgPCvf/2rOjZr1qzwk5/85A6le/bZZ0MA4Y033qjO8TwvnDt37i63uYaGhoaGhoaGhsaBDB2qS2O/wLJly3DWWWeht7cXlmXBcRw899xzWLFixR675v3334+JiQmcffbZ8DxP/b3pTW9CpVLBM888s8V0Dz/8MMIwVKEyAMC2bZx55pm7ZE9jfpZl4YwzzsCDDz4IAFixYgXWrl2Ld7/73TFbTzzxRBiGgUcffXSr+T700EOK0dKIc889F6VSCX/7299ix9/2trfFvt91110488wzYdu2um57ezsOP/xwPPLII7tUZoBCblx33XVYvHgx0uk0HMfB+eefD8/zsGrVqp3K83//938BAO985ztj9XXSSSehv78f69atU+eapok3v/nN6vv8+fORSCSwfv36l7zGttI9/fTTqFarOOOMM2LpdrWfaGhoaGgcWHglz3Gq1SquuOIKzJ8/H8lkEo7j4Itf/CI2bdqEiYmJHc5vR57vwOQ5za5gd5cFoDlWR0cH3vSmN00qz9/+9jf4vq/OnTp1Kg455BD1XRg425qvbCudzOUa5yuWZcVClGpoaGhoaGhoaGi8EqFDdWnscxSLRbzlLW9Bd3c3rr32WsyaNQupVAof/vCHUa1W99h1h4aGAFCYhi2h+eVbsGnTJjiOMynkQ29v707bsqX8enp6sGnTppitjQsZ22MrAIyOjgIApkyZEjsu30dGRtSxTCaDbDYbO29oaAjXXXfdJE0UAEin01u97vbiuuuuw2c/+1lccskleOMb34j29nY88sgj+OQnP7nT7T80NIQwDNHV1bXF39etW4dZs2YBoDIkEonY747jbPPa20onbdfd3R07p6enZ/sLoqGhoaFxQOOVPsf5/Oc/jx/84Ae44oor8KpXvQptbW24/fbb8a//+q+oVqvI5XI7lN+OPN+3NKfZFezusgBUnpGRka2G2tq0aROmT58OAGhra4v9JnOQbfWjbaWTNm9tbY2dp+crGhoaGhoaGhoar3TojRONfY4HHngA69evx29/+1scfvjh6nihUFAvi3sCHR0dAIBf/vKXmDFjxqTfRcizGX19fXBdF6Ojo7GFhc2bN++0LVvKb2BgQMW/Flu/853v4Nhjj52UfurUqVvNW9Ju3rwZ06ZNU8f7+/tjvwPYoghoR0cHTjvtNHziE5+Y9Fs+n3/Jcm0Pbr31Vpxxxhm4+uqr1bGlS5fuUp4dHR0wDAP33nvvpM0NADj44IN3Kf/tgbTd4OBgrH0GBgb2+LU1NDQ0NPYPvNLnOLfeeis+9rGP4fOf/7w6dscdd+xLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1650x462 with 5 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"before = np.load(GRID / FLAT_RUN / 'subpixel_phase_before.npy')\n",
|
||||
"after = np.load(GRID / FLAT_RUN / 'subpixel_phase_after.npy')\n",
|
||||
"\n",
|
||||
"fig, axes = plt.subplots(1, 3, figsize=(15, 4.2))\n",
|
||||
"for ax, histogram, title in ((axes[0], before, 'before flattening'),\n",
|
||||
" (axes[1], after, 'after flattening')):\n",
|
||||
" im = ax.imshow(histogram.T / histogram.mean(), origin='lower', extent=[0, 1, 0, 1],\n",
|
||||
" vmin=0.9, vmax=1.1, cmap='viridis')\n",
|
||||
" ax.set_title(f'flat field, {title}', fontsize=10)\n",
|
||||
" ax.set_xlabel('sub-pixel x'); ax.set_ylabel('sub-pixel y')\n",
|
||||
" plt.colorbar(im, ax=ax, fraction=0.046)\n",
|
||||
"for histogram, title in ((before, 'before'), (after, 'after')):\n",
|
||||
" profile = histogram.sum(axis=1)\n",
|
||||
" axes[2].plot(np.linspace(0, 1, len(profile)), profile / profile.mean(), lw=1, label=title)\n",
|
||||
"axes[2].axhline(1, color='k', lw=.6); axes[2].set_xlabel('sub-pixel x')\n",
|
||||
"axes[2].set_ylabel('relative density'); axes[2].legend(); axes[2].grid(alpha=.3)\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "1cc3ca80",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4. Relative DQE"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "87158001",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:12.379977Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:12.379792Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:12.483482Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:12.483250Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"variant QE rel MTF(200) DQE rel (relative to GridBased flat)\n",
|
||||
"GridBased flat 1.000 0.222 0.049\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# DQE(f) is proportional to QE * MTF(f)^2. Every chain sees the same beam, so\n",
|
||||
"# the ratio of detected photons is the ratio of QE and the relative DQE is well\n",
|
||||
"# defined even without the absolute incident flux.\n",
|
||||
"def mtf_at(frequency_lpmm, sigma_gauss_um):\n",
|
||||
" sigma_mm = sigma_gauss_um / 1000.0\n",
|
||||
" return float(np.exp(-2 * np.pi**2 * sigma_mm**2 * frequency_lpmm**2))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"FREQUENCY = 200.0 # lp/mm, the Nyquist of the 2.5 um bins\n",
|
||||
"REFERENCE = 'GridBased flat'\n",
|
||||
"reference_photons = results[REFERENCE]['photons']\n",
|
||||
"print(f\"{'variant':16s} {'QE rel':>8} {'MTF(200)':>9} {'DQE rel':>9} (relative to {REFERENCE})\")\n",
|
||||
"relative_dqe = {}\n",
|
||||
"for name, r in results.items():\n",
|
||||
" qe = r['photons'] / reference_photons\n",
|
||||
" mtf200 = r['mtf200_lsf'] # measured from the LSF, as in the poly notebook\n",
|
||||
" relative_dqe[name] = qe * mtf200**2\n",
|
||||
" print(f'{name:16s} {qe:8.3f} {mtf200:9.3f} {relative_dqe[name]:9.3f}')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "facc1139",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 5. Summary"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "575e8e9c",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:12.484541Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:12.484461Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:12.588463Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:12.588198Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{\n",
|
||||
" \"GridBased flat\": {\n",
|
||||
" \"sigma_um\": 1.473126548845613,\n",
|
||||
" \"sigma_err_um\": 0.016628349232745622,\n",
|
||||
" \"mtf50_lsf_lpmm\": 133.0356249682,\n",
|
||||
" \"mtf200_lsf\": 0.22230766940089752,\n",
|
||||
" \"chi2_ndf\": 1.2970189194700865,\n",
|
||||
" \"mtf50_lpmm\": 127.2060606579405,\n",
|
||||
" \"mtf10_lpmm\": 231.8477669544846,\n",
|
||||
" \"rows_kept\": 1.0,\n",
|
||||
" \"photons\": 686836853.0\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"written to /mnt/sls_det_storage/moench_data/MLXID/InferenceResults/GridBased/Edge_0filters_12keV/knife_edge_comparison.json\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"summary = {\n",
|
||||
" 'measurement': 'Edge/Flat_0filters_12keV',\n",
|
||||
" 'occupancy_percent': occupancy * 100, # flat field, ESF ROI\n",
|
||||
" 'roi_superpixel': list(ROI),\n",
|
||||
" 'bin_um': BIN_UM,\n",
|
||||
" 'bin_width_um': BIN_WIDTH_UM,\n",
|
||||
" 'convention': 'sigma = ODR p2 (Gaussian LSF); MTF50 = 1000 sqrt(ln 2 / 2) / (pi sigma); '\n",
|
||||
" 'ESF from DeepLearning/src, bin width 0.3 um',\n",
|
||||
" 'grid_model_epoch': grid_summary['epoch'],\n",
|
||||
" 'grid_frames': grid_summary['n_frames'],\n",
|
||||
" 'grid_subpixel_before': grid_summary['subpixel_nonuniformity_before'],\n",
|
||||
" 'grid_subpixel_after': grid_summary['subpixel_nonuniformity_after'],\n",
|
||||
" 'variants': {name: dict(sigma_um=float(r['sigma']), sigma_err_um=float(r['sigma_err']),\n",
|
||||
" mtf50_lsf_lpmm=float(r['mtf50_lsf']),\n",
|
||||
" mtf200_lsf=float(r['mtf200_lsf']),\n",
|
||||
" chi2_ndf=float(r['chi2_ndf']),\n",
|
||||
" mtf50_lpmm=float(r['mtf50']), mtf10_lpmm=float(r['mtf10']),\n",
|
||||
" rows_kept=float(r['rows_kept']), photons=float(r['photons']))\n",
|
||||
" for name, r in results.items()},\n",
|
||||
" 'relative_dqe_200lpmm': relative_dqe,\n",
|
||||
"}\n",
|
||||
"print(json.dumps(summary['variants'], indent=1))\n",
|
||||
"out = GRID / EDGE_RUN / 'knife_edge_comparison.json'\n",
|
||||
"json.dump(summary, open(out, 'w'), indent=1)\n",
|
||||
"print(f'\\nwritten to {out}')"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "pytorch_nightly",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.18"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,569 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "116b7266",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Knife edge, 1 filter — GridBased against eta interpolation\n",
|
||||
"\n",
|
||||
"The second-highest flux point of the scan: **4.45 % occupancy** (flat field,\n",
|
||||
"inside the ESF ROI), 6.0x the 3-filter point and above where the cluster chain was ever\n",
|
||||
"operated.\n",
|
||||
"\n",
|
||||
"The cluster-based CNN images for this run exist only for older model\n",
|
||||
"versions and without the eta-flattening step, so they would not be\n",
|
||||
"comparable with the other two notebooks and are left out. Eta\n",
|
||||
"interpolation is available and is kept as the classical reference.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**Edge width (revised 2026-09-28).** The ESF is binned and fitted exactly as\n",
|
||||
"`Plotting/fig_knife_edge.py --fit odr` does it: `generate_presampled_esf()` and\n",
|
||||
"`get_odr_fitting()` from `DeepLearning/src/funcs_postprocess.py` (bin content\n",
|
||||
"Σk/Σf), symmetric ±4σ window, **ESF bin width 0.3 µm**. The ODR model is\n",
|
||||
"`p0/2 (1 + erf((x - p1)/(sqrt(2) sigma))) + p3`, so the fit gives **sigma**, the\n",
|
||||
"width of the Gaussian LSF, which is what the tables quote, with\n",
|
||||
"`MTF50 [lp/mm] = 1000 sqrt(ln 2 / 2) / (pi sigma)`; MTF50 and MTF(200 lp/mm) are\n",
|
||||
"also measured from the LSF (`Plotting/knife_edge_numbers.py`: first crossing,\n",
|
||||
"central-difference correction), and the relative DQE uses the latter. Only the\n",
|
||||
"flattened GridBased reconstruction is analysed. Same processing as\n",
|
||||
"`KnifeEdge_poly2to20keV_Moench040.ipynb`.\n",
|
||||
"\n",
|
||||
"**Occupancy** is that of the flat field inside the ESF ROI: the reconstructed\n",
|
||||
"photons per 25 µm pixel per frame over `ROI // 10` (x 33–46, y 26–49 of the\n",
|
||||
"99 × 99 frame), the pixels over which `DeepLearning/Notebooks/KnifeEdge_3filters_pos0.ipynb`\n",
|
||||
"sums the deposited energy (0.705 % at 3 filters from the energy, 0.747 % here\n",
|
||||
"from the photons of the 12 keV model).\n",
|
||||
"\n",
|
||||
"*Until 2026-09-28 this notebook took the fitted sigma for sqrt(2) sigma (so its\n",
|
||||
"MTF50 was sqrt(2) too high), used 0.5 µm bins, and binned the ESF with an older\n",
|
||||
"copy of `generate_presampled_esf` (inverse-variance mean of k/f, biased low in\n",
|
||||
"the toe, sigma ~3 % too small). The previous version is in\n",
|
||||
"`Backup_260928_pre_sigma_fix/`.*\n",
|
||||
"\n",
|
||||
"The ROI, the oversampled ESF and the erf fit are the ones from\n",
|
||||
"`DeepLearning/Notebooks/KnifeEdge_3filters_pos0.ipynb`; the edge sits at the\n",
|
||||
"same place at all three flux points, so the same ROI holds throughout and the\n",
|
||||
"three notebooks are directly comparable.\n",
|
||||
"\n",
|
||||
"Run in the `pytorch_nightly` environment (ROOT + scipy + jupyter)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "3975e8f9",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:03.371301Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:03.371220Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:05.007618Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:05.007252Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Welcome to JupyROOT 6.28/10\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import json\n",
|
||||
"import sys\n",
|
||||
"from pathlib import Path\n",
|
||||
"\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"REPO = Path('/home/xie_x1/MLXID/GridBased')\n",
|
||||
"sys.path.insert(0, '/home/xie_x1/MLXID/DeepLearning/src') # the code Plotting/ uses\n",
|
||||
"sys.path.insert(0, '/home/xie_x1/MLXID/Plotting')\n",
|
||||
"from ROOT import TCanvas, gROOT\n",
|
||||
"gROOT.SetBatch(True)\n",
|
||||
"from funcs_postprocess import generate_presampled_esf, get_odr_fitting\n",
|
||||
"from knife_edge_numbers import mtf as mtf_from_lsf # first crossing, sinc-corrected\n",
|
||||
"\n",
|
||||
"GRID = Path('/mnt/sls_det_storage/moench_data/MLXID/InferenceResults/GridBased')\n",
|
||||
"PUBLISHED = Path('/home/xie_x1/MLXID/DeepLearning/InferenceResults')\n",
|
||||
"ETA = Path('/home/xie_x1/MLXID/EtaInterpolation/Results')\n",
|
||||
"\n",
|
||||
"EDGE_RUN, FLAT_RUN = 'Edge_1filters_12keV', 'Flat_1filters_12keV'\n",
|
||||
"BIN_UM = 2.5 # super-pixel = 25 um / 10\n",
|
||||
"ROI = (330, 465, 260, 490) # x1, x2, y1, y2, as published\n",
|
||||
"CROP = slice(10, -10) # 1010 -> 990, as published\n",
|
||||
"BIN_WIDTH_UM = 0.3 # presampled ESF bin, as Plotting/ and the manuscript\n",
|
||||
"\n",
|
||||
"plt.rcParams.update({'figure.dpi': 110, 'image.cmap': 'gray',\n",
|
||||
" 'image.origin': 'lower', 'image.interpolation': 'nearest'})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8c496448",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1. Load every reconstruction of the same measurement"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "4bcf2cfb",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:05.009178Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:05.008836Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:05.131827Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:05.131438Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"GridBased model epoch 135, 7,000,000 frames, occupancy 4.450 % (flat field, ESF ROI)\n",
|
||||
" sub-pixel excess rms 19.8 % -> 3.0 % after flattening\n",
|
||||
"\n",
|
||||
"variant edge photons flat photons relative\n",
|
||||
"eta 2.3085e+08 3.9229e+08 0.407\n",
|
||||
"GridBased flat 5.6697e+08 9.8283e+08 1.000\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def crop(image):\n",
|
||||
" \"\"\"The published frames are cropped by 10 super-pixels on each side.\"\"\"\n",
|
||||
" return image[CROP, CROP] if image.shape[0] == 1010 else image\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"for run in (EDGE_RUN, FLAT_RUN):\n",
|
||||
" if not (GRID / run / 'summary.json').exists():\n",
|
||||
" raise SystemExit(\n",
|
||||
" f'{run} has not been reconstructed yet. Run:\\n'\n",
|
||||
" f' python scripts/05_infer_measurement.py '\n",
|
||||
" f'--config Configs/infer_measurement_12keV.yaml --run {run}')\n",
|
||||
"\n",
|
||||
"grid_summary = json.load(open(GRID / EDGE_RUN / 'summary.json'))\n",
|
||||
"flat_summary = json.load(open(GRID / FLAT_RUN / 'summary.json'))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def grid_image(run, flattened):\n",
|
||||
" name = 'binned_image_flattened.npy' if flattened else 'binned_image.npy'\n",
|
||||
" return np.load(GRID / run / name).astype(float)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"variants = {\n",
|
||||
" 'eta': (np.load(ETA / '2603MaxIV_Edge1Filters_12keV_fromClusters.npy'),\n",
|
||||
" np.load(ETA / '2603MaxIV_Flat1Filters_12keV_fromClusters.npy')),\n",
|
||||
" 'GridBased flat': (grid_image(EDGE_RUN, True), grid_image(FLAT_RUN, True)),\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"# The cluster-based CNN images for this flux point exist only for older model\n",
|
||||
"# versions (folders 260512_1ph.. / 260511_2ph.. / 260529_3ph..) and without the\n",
|
||||
"# eta-flattening step, so they are not comparable with the other two notebooks\n",
|
||||
"# and are left out. Eta interpolation is available and is kept.\n",
|
||||
"\n",
|
||||
"ORDER = ['eta', 'GridBased flat']\n",
|
||||
"variants = {name: (crop(e), crop(f)) for name, (e, f) in variants.items()}\n",
|
||||
"variants = {name: variants[name] for name in ORDER}\n",
|
||||
"\n",
|
||||
"def flat_occupancy(run):\n",
|
||||
" # reconstructed photons per 25 um pixel per frame in the flat field, inside the\n",
|
||||
" # ESF ROI: ROI // 10 in pixels of the 99 x 99 frame, both ends included as in\n",
|
||||
" # DeepLearning/Notebooks; +1 because the 101 x 101 frame is cropped by 1 px\n",
|
||||
" summary = json.load(open(GRID / run / 'summary.json'))\n",
|
||||
" native = np.load(GRID / run / 'native_image.npy') / summary['n_frames']\n",
|
||||
" x0, x1, y0, y1 = (v // 10 for v in ROI)\n",
|
||||
" return float(native[y0 + 1:y1 + 2, x0 + 1:x1 + 2].mean())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"occupancy = flat_occupancy(FLAT_RUN)\n",
|
||||
"print(f\"GridBased model epoch {grid_summary['epoch']}, \"\n",
|
||||
" f\"{grid_summary['n_frames']:,} frames, \"\n",
|
||||
" f\"occupancy {occupancy*100:.3f} % (flat field, ESF ROI)\")\n",
|
||||
"print(f\" sub-pixel excess rms {grid_summary['subpixel_nonuniformity_before']*100:.1f} % -> \"\n",
|
||||
" f\"{grid_summary['subpixel_nonuniformity_after']*100:.1f} % after flattening\\n\")\n",
|
||||
"print(f\"{'variant':16s} {'edge photons':>14} {'flat photons':>14} relative\")\n",
|
||||
"reference = variants['GridBased flat'][0].sum()\n",
|
||||
"for name, (e, f) in variants.items():\n",
|
||||
" print(f'{name:16s} {e.sum():14.4e} {f.sum():14.4e} {e.sum()/reference:8.3f}')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "21d95658",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:05.133060Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:05.132975Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:05.482855Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:05.482542Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAABUkAAAH1CAYAAADLW38kAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AAEAAElEQVR4nOy9eXxcZdn//5lJMvuWrTu0WMRSKULVsgktuxRkERUqKgUVERUXig8PChR+bsimwuPCIpuyCAqirSBI4RFl+eICYvvIDm1p0zTJZPaZZOb8/ujrc+eaO2cmaZrQNrner1deSc6c5T73Ocm5zuf+XNftcRzHgaIoiqIoiqIoiqIoiqIoygTFu70boCiKoiiKoiiKoiiKoiiKsj1RkVRRFEVRFEVRFEVRFEVRlAmNiqSKoiiKoiiKoiiKoiiKokxoVCRVFEVRFEVRFEVRFEVRFGVCoyKpoiiKoiiKoiiKoiiKoigTGhVJFUVRFEVRFEVRFEVRFEWZ0KhIqiiKoiiKoiiKoiiKoijKhEZFUkVRFEVRFEVRFEVRFEVRJjQqkiqKoiiKoiiKoiiKoiiKMqFRkVRRFEVRFEVRFEVRFEVRlAmNiqSKoig7Kbfccgs8Hg8ee+yxUd3vY489Bo/Hg1tuuaVqeS6Xw7nnnotdd90VDQ0NmDVr1qgedzRYtGjRDtmubaXWNamHx+PB0qVLx6xNY3X/bS+WLl0Kj8cz7PVnzZqFRYsWVS0b6f03kus7GozXvxdFURRFURRFGQkqkiqKoijD4vLLL8e1116LU045Bbfccgt+8IMfbO8mTWiSySSWL18+piLlY489huXLlyOZTI7ZMZSdg1mzZsHj8dT8Wr58edX6r7/+Oj7/+c9jzz33RDgcRiKRwB577IFTTz0Vv/nNb6rWXbRoUc397r777kO2bfny5VXbeL1eJBIJHHzwwbj99tvrbvvQQw/hpJNOwtSpU+Hz+dDe3o6jjz4ad911FxzHqXmsJ554YuhOUxRFURRFUXYqGrd3AxRFUZQdi0MOOQT5fB5NTU1Vyx9++GHMmzcPV1xxxXZq2cTF7Zokk0lceumlADDI0ThaPPbYY7j00kuxdOlSJBKJMTnGeOKPf/yjq7A2Xpg8eTKuvPJK18/23ntv8/Pf//53HHLIISiXyzjttNPwxS9+EQDw8ssvY8WKFchkMvjwhz9ctb3X68Wtt946aL/RaHTY7bvooouwxx57oFwu480338SNN96IT33qU1i/fj0uuOCCqnUrlQrOPvts3HDDDZg9ezbOOusszJw5Ex0dHbjnnnuwZMkS3HHHHbj77rsRDAaH3QZFURRFURRl50VFUkVRFKUKr9eLQCAwaPnGjRux6667bocWKbWuibJj4fP5tncTxpRIJIJPfOITQ663fPlyZLNZ3H///TjhhBOqPrvmmmuwbt26Qdt4PJ5h7bseRx11FD7wgQ+Y388880zsscceuPzyy3H++eejoaHBfPatb30LN9xwA04++WT88pe/hN/vN59dcMEFWLZsGa6++mp88YtfxE033bRN7VIURVEURVF2DjTdXlEUZZzxk5/8BI2NjfjYxz6GYrEIYKB+4osvvogTTjgB8XgckUgExx57LF555ZWq7e36iEwvfe211/D444+7ptf+4x//wEc+8hFMmjQJPp8P73jHO3DBBRcgl8sNu92vvPIKli5dimnTpsHn82HGjBk455xzsHnz5kHrvvzyyzjppJMQj8cRjUZx1FFH4bnnnqu579tvvx177703/H4/ZsyYga9//etYs2aNa5qw4zi44YYbsGDBAoTDYYTDYRx44IG4//77h30uNuvXr4fH48F5551Xtfyss86Cx+PB5z73uarlX/va1+DxeNDR0QFg8DW55ZZbsNtuuwEALr30UnNN3OpLPvPMMzjssMMQiUSQSCSwZMkSdHZ2DtnmRYsWGafqbrvtVjOt2nEc/OAHP8Aee+wBv9+Pd7zjHbjmmmtc97mt9wlraL7xxhs4+eST0dzcjHA4jCOPPBL//Oc/q9atV+eT9/Trr78+6LOuri6ceeaZaG9vRzAYxIEHHohHH310q9onWbNmDZYsWYJddtkFfr8fkyZNwkEHHYSbb77ZdR+8VwOBAKZPn45vfOMbKJfLg9Yby7+XbeXFF18EABx++OGun8+YMWPMji2ZPn069txzTySTyap7fvPmzfje976H6dOn49Zbb60SSIEtgu0VV1yB9773vbj55pvx73//+21pr6IoiqIoirJ9USepoijKOMFxHPz3f/83Lr/8cnz1q1/FVVddVTURzfr163HIIYfg+OOPx+WXX46XXnoJ1157LY4//nj861//gtfrPm724Q9/GLvvvju++tWvoq2tDd/4xjcADKTXPvjggzjxxBOxyy674Etf+hImT56M5557DldffTX+8pe/YNWqVWhsrP+4+ec//4lFixYhFArhzDPPxMyZM/HSSy/hJz/5Cf70pz/hmWeeQTweBwCsXbsWBx54IJLJJM4++2zsueeeePLJJ7Fo0SK0trYO2vf//M//4Itf/CLmzJmDSy+9FE1NTbjzzjtr1vI844wzcNttt+GEE07AaaedBgD4zW9+g5NOOgk/+clPcPbZZ9e/EC5Mnz4dc+bMwSOPPFK1/E9/+hO8Xq/r8r322guTJ0923d8hhxyCa665Bl/96ldx0kknmdTlSCRStd5zzz2HY445Bp/61Kdwyimn4G9/+xtuvPFG9PT04MEHH6zb5m984xtoaWnBfffdh2uuuQZtbW0AqtOqAeDCCy9EKpXCGWecgUgkgttuuw1f+9rXMHXqVJx66qlmvdG4TwAgm81i4cKF2HffffGtb30La9euxf/8z//g4IMPxpNPPom99tpryH3U4+ijj0YsFsNFF12E7u5u/PSnP8XRRx+NP/zhDzjiiCO2al9dXV049NBDUalU8LnPfQ677bYbenp68K9//QuPP/44zjjjjKr1f/azn2H9+vX4zGc+g/b2dvzmN7/Bd77zHUSj0ap08bH8e6lHpVJxFWEBIJFImOs3e/Zs/Oc//8GNN96IL3/5y8OeEMtt3/F4fFDpj+FSKpWwdu1aU6OUrFixAvl8Hp/85CcRDoddt/V6vTjrrLPwuc99Dr/+9a/x7ne/e0RtUBRFURRFUXYiHEVRFGWn5Oabb3YAOKtWrXIKhYJz6qmnOl6v1/nhD384aN2ZM2c6AJw77rijavl3v/tdB4Dz0EMPmWWrVq1yADg333zzoH0sXLiwalk+n3emTJniLFiwwCkUClWf3XPPPQ4A55ZbbhnyXPbZZx9nt912c7q6uqqWP/XUU47X63WWL19uln3yk590ADj33Xef67nMnDnTLOvp6XHC4bDzjne8w0mlUmZ5oVBw3v/+9zsAnEsuucQsv//++x0AztVXXz2ojccdd5wTi8Wq9rM1fOELX3A8Ho/T0dHhOI7jvPbaaw4Acz6vvvqq4ziOs2nTJsfj8Thf/vKXzbZu14Tby/ZLADgej8d54oknqpZ/7nOfcwA4//nPf4Zs8yWXXOIAcF577bVBn/H+23vvvauufSaTcVpbW50DDjjALBut+2ThwoUOAOcLX/hC1fKnn37a8Xg8zuGHH26W1bqPa53X6aef7gBwPvShDznlctksf/31151QKOS8853vdCqVilnu9vewcOHCqvvvt7/9rQPAueuuu+qeF9s6ZcoUp7u72ywvl8vOnnvu6UydOrVq/bH6e6kH/4fU+vrzn/9c1Q6fz+cAcHbddVfnU5/6lHPttdc6//znP133zevq9vWHP/xhyLbxev7+9793Ojs7nY6ODueZZ55xTjrpJAeAc+qpp1atf9555zkAnF//+td19/vss886AJyTTz550LHk+SqKoiiKoijjA023VxRF2cnp6enBUUcdhfvvvx/33HMPzj33XNf1pk2bhiVLllQtO/LIIwEMpMduLY888gg2btyIpUuXIp1OY/PmzeZr4cKFCIfDeOihh+ru44UXXsA///lPnHrqqcapxq/Zs2fjne98p9lHpVLB/fffj7lz5+LEE0+s2s9XvvKVQU7KP/7xj8hmszjnnHOqJoDx+/346le/Oqgtt99+O4LBIE455ZSqdmzevBknnXQSUqkUnnzyyRH11eGHHw7HcUzq9p/+9Cc0NDTg0ksvRUNDA/70pz8BAB599FE4jlMzVXlrOOCAA3DQQQdVLdvWa27zxS9+sSpdORwO44ADDqja/2jcJ5ILL7yw6vcFCxbgiCOOwKOPPoqenp5tOp///u//rnJVz5w5E6eddhpeeuklPP/881u1L7oXV65cid7e3iHXP/PMM9Hc3Gx+93q9OPzww7FhwwZkMhkAY/v3MhTTpk3Dww8/7Po1b948s95+++2Hv//97/j0pz+N/v5+3HbbbfjSl76EffbZB/Pnzx9UGoHn6rbf97///cNu33HHHYf29nZMnjwZCxYswAMPPIDPf/7zg2qK8lrQbVsLfj6ca6coiqIoiqLs/Gi6vaIoyk7O0qVLkUql8PDDD9dNB37HO94xaBnTbbu6ukZ07DVr1gAAzjnnHJxzzjmu67Cu5lD7+O53v4vvfve7ruuw7Zs2bUI6ncbcuXMHrRMIBDB79mwkk0mz7NVXXwUAzJkzZ9D6e+65p2tb8vk8pk+fXrO9Q51PLQ499FCTWn/qqafikUcewXvf+17stttumD9/Ph555BF85jOfwSOPPIKGhgYsXLhwRMeRjMU1H+4x5P5H4z4hiUQC06ZNG7R87ty5ePjhh/Hqq6/ive9977D25YbbvcVlL7/8Mt7znvcMe1+HHHIIzjzzTPz85z/HnXfeife+97048MAD8ZGPfAQHHHDAoPWHul6RSGRM/16GIhgMDrvkwLvf/W7ceOONAIB169bhL3/5C2677TasXLkSixcvxr///e8qQdjj8Wx1OQOba665BnvttRfy+TyefPJJXHnlldi4ceOgdP1Line truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1650x506 with 4 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"fig, axes = plt.subplots(1, len(ORDER) if len(ORDER) < 4 else 3, figsize=(15, 4.6))\n",
|
||||
"extent = [0, 990 * BIN_UM, 0, 990 * BIN_UM]\n",
|
||||
"shown = ORDER if len(ORDER) < 4 else ['eta', 'cluster <=3ph', 'GridBased flat']\n",
|
||||
"for ax, name in zip(np.atleast_1d(axes), shown):\n",
|
||||
" image = variants[name][0]\n",
|
||||
" im = ax.imshow(image, extent=extent, vmax=np.percentile(image, 99.5))\n",
|
||||
" ax.add_patch(plt.Rectangle((ROI[0]*BIN_UM, ROI[2]*BIN_UM),\n",
|
||||
" (ROI[1]-ROI[0])*BIN_UM, (ROI[3]-ROI[2])*BIN_UM,\n",
|
||||
" edgecolor='red', facecolor='none', lw=1.4))\n",
|
||||
" ax.set_title(name); ax.set_xlabel('x [um]'); ax.set_ylabel('y [um]')\n",
|
||||
" plt.colorbar(im, ax=ax, fraction=0.046)\n",
|
||||
"fig.suptitle('knife edge, with the published ESF ROI')\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "782d9a37",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2. Edge spread function\n",
|
||||
"\n",
|
||||
"`generate_presampled_esf` fits an erf to every row of the ROI, fits a straight\n",
|
||||
"line through the edge positions, and re-samples the ROI onto a common axis;\n",
|
||||
"`get_odr_fitting` then fits the erf with x and y errors inside |x - p1| <= 4 sigma\n",
|
||||
"(the fit of `Plotting/fig_knife_edge.py --fit odr`)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "7a741198",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:05.484058Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:05.483960Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:06.360573Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:06.360259Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Final Edge Midpoint Fit: slope = -0.0859, intercept = 432.5449, chi2/ndf = 0.0615\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0852, intercept = 432.6254, chi2/ndf = 0.0434\n",
|
||||
"variant sigma [um] chi2/ndf MTF50 MTF50 LSF MTF(200) LSF rows\n",
|
||||
"eta 1.506 +- 0.023 1.83 124.4 130.0 0.218 100%\n",
|
||||
"GridBased flat 1.388 +- 0.020 1.82 135.0 141.3 0.251 100%\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def analyse(edge_image, flat_image, label):\n",
|
||||
" esf = generate_presampled_esf(edge_image, flat_image, ROI,\n",
|
||||
" pixel_size_um=BIN_UM, bin_width_um=BIN_WIDTH_UM,\n",
|
||||
" chi2_threshold=15.0, residual_tolerance_px=1.0)\n",
|
||||
" x, z = esf['numpy']['x'], esf['numpy']['z']\n",
|
||||
" odr = get_odr_fitting(x, z, esf['numpy']['x_err'], esf['numpy']['z_err'], n_sigma=4.0)\n",
|
||||
" sigma, sigma_err = odr['sigma_um'], odr['sigma_err_um'] # sigma of the Gaussian LSF\n",
|
||||
" try:\n",
|
||||
" mtf50_lsf, mtf200_lsf = mtf_from_lsf(dict(x=x, z=z, pars=odr['beta']))\n",
|
||||
" except Exception:\n",
|
||||
" mtf50_lsf = mtf200_lsf = np.nan\n",
|
||||
" n_fit = int(odr['mask'].sum())\n",
|
||||
" ndf = max(n_fit - len(odr['beta']), 1)\n",
|
||||
" x_fit = x[odr['mask']]\n",
|
||||
" return dict(label=label, x=x, z=z, sigma=sigma, sigma_err=sigma_err, sigma_gauss=sigma,\n",
|
||||
" chi2_ndf=odr['chi2_ndf'], chi2=odr['chi2_ndf'] * ndf, ndf=ndf,\n",
|
||||
" mtf50=1000 * np.sqrt(np.log(2) / 2) / (np.pi * sigma),\n",
|
||||
" mtf10=1000 * np.sqrt(np.log(10) / 2) / (np.pi * sigma),\n",
|
||||
" mtf50_lsf=mtf50_lsf, mtf200_lsf=mtf200_lsf,\n",
|
||||
" rows_kept=esf['valid_lines_ratio'],\n",
|
||||
" edge_slope=esf['edge_slope'], edge_centre=odr['beta'][1],\n",
|
||||
" fit_points=n_fit, fit_range=(x_fit.min(), x_fit.max()),\n",
|
||||
" photons=float(edge_image.sum()), odr=odr)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"results = {name: analyse(edge, flat, name) for name, (edge, flat) in variants.items()}\n",
|
||||
"\n",
|
||||
"print(f\"{'variant':16s} {'sigma [um]':>16} {'chi2/ndf':>9} {'MTF50':>7} {'MTF50 LSF':>9} \"\n",
|
||||
" f\"{'MTF(200) LSF':>12} {'rows':>6}\")\n",
|
||||
"for name, r in results.items():\n",
|
||||
" print(f\"{name:16s} {r['sigma']:7.3f} +- {r['sigma_err']:.3f} {r['chi2_ndf']:9.2f} {r['mtf50']:7.1f} \"\n",
|
||||
" f\"{r['mtf50_lsf']:9.1f} {r['mtf200_lsf']:12.3f} {r['rows_kept']*100:5.0f}%\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "5b1a1427",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:06.361862Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:06.361744Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:06.749047Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:06.748786Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAABVMAAAIECAYAAAAU8b4kAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AAEAAElEQVR4nOzdd3xN9xvA8c+92bmZMiWRROy9txKzqFGrNlEUNdJqKbWVGkWVWm1VULQ1qkXtVbP2Fjt2SCJ739zz+yO/XCJDKLkJz/v1uuSe8z3nPOebm+Tc537P81UpiqIghBBCCCGEEEIIIYQQIltqQwcghBBCCCGEEEIIIYQQ+YEkU4UQQgghhBBCCCGEECIHJJkqhBBCCCGEEEIIIYQQOSDJVCGEEEIIIYQQQgghhMgBSaYKIYQQQgghhBBCCCFEDkgyVQghhBBCCCGEEEIIIXJAkqlCCCGEEEIIIYQQQgiRA5JMFUIIIYQQQgghhBBCiByQZKoQQgghhBBCCCGEEELkgCRThRBCCCGEEEIIIYQQIgckmSqEEG+JoKAgVCoVEyZMyFf7FkIIIYTIK3Q6HRMmTMDHxwdjY2NUKpWhQ3plAgICUKlU7N27N1ePu2fPHmrWrIm1tTUqlYqAgAD27t2r/zov8fX1xdvb29BhCCEMTJKpQgghclXaxXF2j6CgoHTbbN68mXfffRdPT0/MzMxwdXWlWrVq+Pv7c+PGDX27tKRuVo/Jkyfn8tkKIYQQIjtPXxf06tUr0zaKouDt7Y1KpcLY2DjDdjl55GSbX3755bnxLlu2jIkTJ9KgQQOWLFnCihUrXl1n5IK9e/cyYcIEIiIiDB0KAOHh4bRr147Y2FhmzZrFihUrqFevXqZtIyIimDBhQpbJ3jlz5uSp5Gvaazarx7ODEIKCghg4cCClSpVCo9FgZ2dH8eLF6dy5M+vXr0/X1tfXN8v9Fi1aNBfPUoi3k7GhAxBCCPF26tChA23atMl0nZOTk/7rUaNGMW3aNHx8fOjduzeFChUiJCSE8+fPs3TpUt555x18fHzSbe/r60ufPn0y7LdixYqv9ByEEEII8WqYm5uzdu1a5s2bh42NTbp1O3bs4NatW5ibm5OcnAxAqVKlMiQy169fzx9//MFHH33EO++8k+WxsroGqVOnznPj3LFjB7a2tvz000/5clTq3r17mThxIn5+ftjZ2Rk6HI4dO0ZERARLliyhXbt2+uXe3t7Ex8djYmKiXxYREcHEiROB1Gu9Z82ZMwdvb2/8/Pxed9g55uLiwsyZMzNdV758ef3XJ0+epF69eqSkpNCtWzcGDx4MwLVr19i8eTMxMTHp+gdArVazbNmyDPu1trZ+hWcghMiMJFOFECILsbGxaDQaQ4fxxqpQoQLdu3fPtk1ISAjffPMNnp6enDp1KsObq/j4eOLj4zNsV6RIkefuWwghhBB5R7t27Vi1ahWrV6+mf//+6db99NNPeHp64uXlxaFDh4DUJNWzf+uvXbvGH3/8Qa1atbK9DsjJNUhWgoODsbOzy1EiNTExESMjI/1oWpFRcHAwAAUKFEi3XK1WY25uboiQXikrK6scvdYmTJhAbGwsGzZsyJDo//bbb7l7926GbVQqlVzvCmEgcpu/EMLgIiIiGDZsGIULF8bMzAwXFxe6dOnC1atX9W2ioqLQaDQ0adIk032k1Xh6+tNZRVH48ccfqV69OhqNBo1GQ+3atdmwYUOG7VUqFX5+fuzduxdfX19sbGwoW7YskHoh/NVXX1G6dGk0Gg02NjaULFmSPn36kJiYqN/H9u3b6dKlC0WKFMHCwgIbGxvq16/P5s2bMxzPz88PlUrF48eP6du3L87OzlhZWdG0aVP9ef/1119Uq1YNS0tL3N3dmTZtWob9eHt74+vry5kzZ2jatCnW1tbY2trSvn17bt68mbNvALBu3Trq16+PjY0NFhYWVKpUiZ9++inTtqtXr6ZChQqYm5vj7u7OsGHDiIuLy/GxXsT169dJSUmhWrVqGRKpABYWFhkuvoUQQgiR/5QqVYratWuzZMmSdMtDQ0P5888/6d27N2q14d6+pl1r7tmzh1u3bulvqU4bBZlWS/PWrVt07twZR0dHzM3N9Umwe/fu0bdvX9zd3TE1NcXDw4OPPvqIBw8epDvO07VCf/jhB0qXLo25uTnFixdn+fLl+n117twZBwcHNBoN77//vj4pmR1fX1/9yM7ChQtnebu5oijMmTOH4sWLY2Zmho+PD99++22m+zx16hQdOnTA2dkZU1NTfHx8GDlyZI6uDZ8u7dCgQYNMSzKk3bYfEBBA4cKFAZg4caK+rbe3t77M061bt9i3b1+WpaOuX7+On58fbm5u+u/Bxx9/TGhoaIbYrl27Rtu2bbG1tcXa2pqmTZty5syZ557Ty7py5QoAjRo1ynS9h4fHazu2EOLFyUdkQgiDio6Opk6dOly8eJFu3bpRu3Ztrl+/zoIFC9i6dSsHDx6kdOnS2NjY0LZtW1avXs3du3czXFAEBARgZWVFhw4d9Mt69+7N8uXLadOmDd26dQNSb/9q27YtCxcuZMCAAen2cfz4cdatW0fv3r3p2rUr0dHRAAwePJiffvqJbt26MXToUABu3rzJxo0biY+Px8zMTB/Dw4cP6d69Ox4eHoSEhLBs2TJatmzJmjVr0sWWplmzZri4uDB+/Hju37/P7Nmzadq0KV999RWfffYZAwYMoHfv3vz666+MGjUKLy8vunTpkm4fd+/epUGDBrRu3ZoZM2Zw8eJFFi9ezOHDhzlx4gQFCxbM9nswYcIEfe2v8ePHY2FhwbZt2+jXrx/Xrl1Ll8RdtGgRAwcOpHjx4owfPx4TExNWrlzJP//8k+0xMhMXF5fpxauRkRH29vYA+Pj4oFKp+Oeff7h8+TIlSpTI0b4TExMz7FutVkviVQghhMjD+vbty4cffsi5c+coV64cAMuXL0er1dK7d+9XNjFSZtcgJiYm2NraZrlNvXr1WLFiBVOmTCE0NFSfXCxSpIi+TUxMDO+88w7Vq1dn4sSJREdHY2Vlxb1796hWrRqPHj2iX79+lC9fnjNnzvDjjz+ydetWjh07houLS7rjLViwgJCQEPr164eVlRU//fQTvXr1wsTEhFGjRvHOO+8wefJkAgMDmT9/Pr169WLbtm3Znvfo0aMpUKAAf/zxB99++y2Ojo5A+tvNAb788kuioqLo3bs3VlZWLF++nGHDhlGwYEE6d+6sb7d161bef/99ChUqxJAhQ3BxceHMmTPMnj2bgwcPsmfPnmxH5a5YsYL9+/fzww8/8OWXX1KqVKls+//bb7/l008/pW3btvpb3q2srHBycmLFihV8+umnODo6Mnr0aP12aaWjTp8+ja+vL5aWlnz44Yd4eXlx9epVFi5cyK5duzh69Kj++3/nzh1q165NREQEAwYMoFSpUhw+fBhfX18cHByy7eNn6XS6TK93Aezs7PT9U6RIES5fvsxPP/2Ev79/jktIZLZvW1vbdOURhBCvgSKEEAY0duxYBVCmT5+ebvnevXsVQGnUqJF+2c6dOxVAmTJlSrq2N27cUFQqldK7d2/9sg0bNiiAMnv27AzHbNmypWJjY6NERUXplwEKoGzfvj1De3t7e6VZs2bPPZeYmJgMy2JjY5XixYsrZcqUSbe8V69eCqD0798/3fJvv/1WARQrKyvl5s2b+uUJCQmKi4uLUqtWrXTtvby8FED55ptv0i3//fffFUDp06ePftnNmzcVQBk/frx+2alTpxSVSqUMHTo0Q+yDBg1S1Gq1cv36dUVRFCUiIkKxsrJSPD09lYiICH27uLg4pWLFihn2nZU9e/bo+zuzR5EiRdK19/f3VwDFyMhIqVGjhjJs2DDlt99+Ux49epRh32nnmNnDxcXlubEJIYQQInelXRd89dVXSkxMjGJtba34+/vr15cuXVpp2rSpoiiKUr9+fcXIyCjLfY0fP14BlKVLl2Z7rMweNWrUyFG89evXV7y8vDJdDihffvllhnU9evRQAOW3335Lt3zZsmUZrtfSYnR1dVUeP36sXx4cHKyYmZkpKpUqw3Vz2rXS5cuXnxt/Wh89fZ2ZZunSpQqglC9fXklISNAvj4mJURwcHNJdh8bHxyuurq5K9erV07VVFEVZs2aNAigBAQHPjSftmHv27Em3PK0fnv5eZnYt+zQvLy+lfv36ma6rWLGiUrhwYSUsLCzd8iNHjihqtVqZMGGCflna9+uPP/5I13bq1KkKkOn3P6t4srvm3b9/f7o4TE1NFUDx9PRUevbsqcybN085ffp0pvtOe71l9tiyZUuO4hNCvDy5zV8IYVDr1q3D1tYWf3//dMvr169PgwYN2L17N+Hh4QA0bNgQT0/PDIXWly1bhqIo6YrNr1ixAgsLCzp16kRoaGi6R9u2bYmKiuLw4cPp9lOhQoVMywjY2dlx4cIFzp49m+25PF1fNTY2lrCwMOLi4mjYsCEXLlzQj3R92meffZbhvAFat26Nt7e3frmZmRk1atTQ3wL0NGtra4YMGZJuWceOHSlevDjr169HUZQsY/7ll19QFIU+ffpk6Kc2bdqg0+nYuXMnkFrGICYmhsGDB6cbuWFhYcHnn3+eTc9kzs/Pjx07dmR4pN3Clubbb79l5cqV+Pr6cvbsWWbPnk2nTp1wc3Ojf//+mdZMbd68eYb9rlmz5oVjFEIIIUTu0Wg0dO7cmV9++YWkpCQOHTrExYsX6du37ys9TmbXIPPmzXsl+x4+fHi65zqdjg0bNlCyZEk++OCDdOt69OhBkSJFMr1e+/DDD/V36kBqjdgSJUqgUqn0d0qlSbt+zOw68WUMHjxYf+cVpH5fatWqlW7/O3fuJDg4GD8/P6Kjo9NdQ9avXx+NRvPckbK55fz585w+fZrOnTvrR4qmPYoUKUKxYsX0saZ9v0qXLs3777+fbj+ffPIJVlZWL3RsNze3TK93d+zYoR99DVCLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1375x528 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"COLOURS = {'eta': '#a0451c', 'cluster 1ph': '#6b6b6b', 'cluster <=2ph': '#7b5aa6',\n",
|
||||
" 'cluster <=3ph': '#4b2a6b', 'GridBased raw': '#4cbcac', 'GridBased flat': '#10695f'}\n",
|
||||
"frequency = np.linspace(0, 400, 2000)\n",
|
||||
"fig, ax = plt.subplots(1, 2, figsize=(12.5, 4.8))\n",
|
||||
"for name, r in results.items():\n",
|
||||
" ax[0].plot(r['x'], r['z'], lw=1.1, color=COLOURS[name],\n",
|
||||
" label=f\"{name}: $\\\\sigma$ = {r['sigma']:.3f} $\\\\pm$ {r['sigma_err']:.3f} $\\\\mu$m\")\n",
|
||||
" sigma_mm = r['sigma_gauss'] / 1000.0\n",
|
||||
" ax[1].plot(frequency, np.exp(-2 * np.pi**2 * sigma_mm**2 * frequency**2),\n",
|
||||
" lw=1.6, color=COLOURS[name], label=f\"{name} ({r['mtf50']:.0f} lp/mm)\")\n",
|
||||
"ax[0].set_xlim(-9, 9); ax[0].set_ylim(-0.05, 1.35)\n",
|
||||
"ax[0].set_xlabel(r'position across the edge [$\\mu$m]')\n",
|
||||
"ax[0].set_ylabel('relative intensity')\n",
|
||||
"ax[0].legend(fontsize=8); ax[0].grid(alpha=.3); ax[0].set_title('oversampled ESF')\n",
|
||||
"ax[1].axvline(200, color='k', ls=':', lw=.8, label='2.5 um Nyquist')\n",
|
||||
"ax[1].axhline(0.5, color='grey', lw=.5)\n",
|
||||
"ax[1].set_xlim(0, 400); ax[1].set_ylim(0, 1.05)\n",
|
||||
"ax[1].set_xlabel('spatial frequency [lp/mm]'); ax[1].set_ylabel('MTF')\n",
|
||||
"ax[1].legend(fontsize=8); ax[1].grid(alpha=.3); ax[1].set_title('MTF from the fitted ESF')\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "01c38bd2",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3. Where the GridBased sub-pixel phase stands"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "da7da667",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:06.750216Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:06.750108Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:07.141786Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:07.141541Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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V155JcbGxnDppZdidnYWX/3qV/H85z8fP/7xj/Gyl70MF154Id71rnfZOrr44otx7bXX4rLLLsNLXvISfO9738MHPvABLC4u4iMf+YjNR6vVwpvf/GZ84AMfwMc//nEMDAzgsccew+mnn46TTz4Zn//85+G6Lv7qr/4KL3/5y/Hggw+iWCzuUB6GDHnzm9+M448/Hh/5yEd2uh8ATE1NYXBwENdccw0GBgbw0EMP4YorrsD4+Dg++9nPAgB+/OMf4zd+4zfwR3/0R7jwwgsBGBXIk20HgD/+4z/GP//zP+PDH/4wTjvtNNx+++344Ac/iHK5jHe/+925un/LW96C97///fjIRz6Cj3/843jDG96ATZs2YWho6CnbbFfHXXrppfjMZz6Dj33sY3juc5+Lr33ta/iLv/iL3esUCoVCoThooWOc3cPWrVtx3HHH4c1vfjN6enrwi1/8Apdffjmq1So++tGPPul4odls7vXzfWdjmk481dhpT8ryjW98A69//etx1VVXWfXKU20HgN/93d/FD3/4Q1x++eU44YQTcOutt+Itb3kLBgYG8JrXvMaef3x8HO9///tx6aWXore3F5deeinOO+88PProowiC4EnbYHeOe/vb347vf//7+Ou//musXbsWn/nMZ3DXXXftdjsrFAqFQqFQKBSHJVKFYj/ixhtvTAGkjz/+uN32+OOPpwDSG2+8cafHxHGchmGYHnfccemHPvQhu/3yyy9PK5XKPjvvwsJC2t3dnTtHmqbpddddl5bL5XRqaipN0zS97bbbUgDpT3/60zRN0/S+++5LHcdJ/8//+T/2mDAM06OOOirdk0vq8ssvTwHk0ouiKF23bl36pje9KU3TNE2SJF27dq39Ttxyyy2p4zjpPffcY7dVKpX08ssvt98nJyfTIAjSiy++OHfs7//+76eVSiVdXFzM5eNrX/tabr+LLrooXb9+fVqv1+22iYmJtFKppNddd91Tlu2kk05K3/rWt+a2vfWtb01POumkJz0mDMP0y1/+cur7flqtVu12AOnf/M3f7LD/zrY/8sgjqeM46Wc+85nc9osvvjhdtWpVGsdxrsy33HKL3efhhx9OAaRf+tKX7LYzzjgjPfvss+333Tlueno6LZVK6cc+9rFcHs4444wd+qZCoVAoDj3oGOfpIUmSNAzD9K/+6q/S0dHR3G87Gy/si+d755jmydA5dkrTHZ/9u1OWJ2v/J9v+/e9/PwWQfuc738ltP//889NTTjnFfn/rW9+6w3jve9/7Xgog/X//7//ZbWvXrk3f+973Pq3j7r333hRA+sUvftHuE0VRevTRR+91mysUCoVCoVAoFIcyNFSX4qDA/fffj/POOw8rV66E53kIggAPPvggHnroof12zttvvx1LS0s4//zzEUWR/feyl70M9Xod99xzz06Pu+OOO5CmqQ2VAQC+7+Pcc8/dq/y0p+d5Hl73utfhJz/5CQDgoYcewqZNm/C7v/u7ubyeccYZcBwHd95555Om+9///d9W0dKON73pTahWq/j5z3+e2/7a17429/273/0uzj33XPi+b887MDCAX/u1X8NPf/rTvSozYEJuXHvttTjxxBNRLpcRBAHe/OY3I4oiPPbYY3uU5r//+78DAN7whjfk6uvlL385xsfHsXnzZruv67p4xSteYb9v2LABhUIBW7Zsecpz7Oq4u+++G41GA6973etyx+1tP1EoFArFoYVn8hin0Wjg8ssvx4YNG1AsFhEEAT784Q9jbGwMS0tLTzu9p/N8B3Yc0+wN9nVZADPGGhwcxMte9rIdyvPzn/8ccRzbfVevXo2TTjrJfqcCZ1fjlV0dx7Fc+3jF87xciFKFQqFQKBQKheKZCA3VpVh2LC4u4lWvehVGRkZwzTXXYO3atSiVSnjXu96FRqOx3847NTUFwIRp2Bk6X76JsbExBEGwQ8iHlStX7nFedpbeihUrMDY2lstr+0TG7uQVAGZnZwEAq1atym3n95mZGbutq6sLlUolt9/U1BSuvfbaHTxRAKBcLj/peXcX1157Lf78z/8cl1xyCV760pdiYGAAP/3pT/He9753j9t/amoKaZpieHh4p79v3rwZa9euBWDKUCgUcr8HQbDLc+/qOLbdyMhIbp8VK1bsfkEUCoVCcUjjmT7G+eAHP4h/+qd/wuWXX44XvOAF6O/vx80334y//Mu/RKPRQHd399NK7+k833c2ptkb7OuyAKY8MzMzTxpqa2xsDGvWrAEA9Pf3537jGGRX/WhXx7HN+/r6cvvpeEWhUCgUCoVC8UyHLpwolh0//vGPsWXLFnzzm9/Er/3ar9nt8/Pz9mVxf2BwcBAA8I1vfANHHnnkDr/TyLMTo6OjCMMQs7OzuYmF7du373FedpbexMSEjX/NvP7DP/wDTjvttB2OX7169ZOmzWO3b9+OI444wm4fHx/P/Q5gpyagg4ODOPvss/Ge97xnh996enqesly7gxtvvBGve93r8PGPf9xuu++++/YqzcHBQTiOgx/+8Ic7LG4AwHHHHbdX6e8O2HaTk5O59pmYmNjv51YoFArFwYFn+hjnxhtLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1650x462 with 5 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"before = np.load(GRID / FLAT_RUN / 'subpixel_phase_before.npy')\n",
|
||||
"after = np.load(GRID / FLAT_RUN / 'subpixel_phase_after.npy')\n",
|
||||
"\n",
|
||||
"fig, axes = plt.subplots(1, 3, figsize=(15, 4.2))\n",
|
||||
"for ax, histogram, title in ((axes[0], before, 'before flattening'),\n",
|
||||
" (axes[1], after, 'after flattening')):\n",
|
||||
" im = ax.imshow(histogram.T / histogram.mean(), origin='lower', extent=[0, 1, 0, 1],\n",
|
||||
" vmin=0.9, vmax=1.1, cmap='viridis')\n",
|
||||
" ax.set_title(f'flat field, {title}', fontsize=10)\n",
|
||||
" ax.set_xlabel('sub-pixel x'); ax.set_ylabel('sub-pixel y')\n",
|
||||
" plt.colorbar(im, ax=ax, fraction=0.046)\n",
|
||||
"for histogram, title in ((before, 'before'), (after, 'after')):\n",
|
||||
" profile = histogram.sum(axis=1)\n",
|
||||
" axes[2].plot(np.linspace(0, 1, len(profile)), profile / profile.mean(), lw=1, label=title)\n",
|
||||
"axes[2].axhline(1, color='k', lw=.6); axes[2].set_xlabel('sub-pixel x')\n",
|
||||
"axes[2].set_ylabel('relative density'); axes[2].legend(); axes[2].grid(alpha=.3)\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "0d8f058f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4. Relative DQE"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "c3b2ff8f",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:07.143232Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:07.143111Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:07.246698Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:07.246438Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"variant QE rel MTF(200) DQE rel (relative to GridBased flat)\n",
|
||||
"eta 0.407 0.218 0.019\n",
|
||||
"GridBased flat 1.000 0.251 0.063\n",
|
||||
"\n",
|
||||
"highest relative DQE at 200 lp/mm: GridBased flat (3.24x eta)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# DQE(f) is proportional to QE * MTF(f)^2. Every chain sees the same beam, so\n",
|
||||
"# the ratio of detected photons is the ratio of QE and the relative DQE is well\n",
|
||||
"# defined even without the absolute incident flux.\n",
|
||||
"def mtf_at(frequency_lpmm, sigma_gauss_um):\n",
|
||||
" sigma_mm = sigma_gauss_um / 1000.0\n",
|
||||
" return float(np.exp(-2 * np.pi**2 * sigma_mm**2 * frequency_lpmm**2))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"FREQUENCY = 200.0 # lp/mm, the Nyquist of the 2.5 um bins\n",
|
||||
"REFERENCE = 'GridBased flat'\n",
|
||||
"reference_photons = results[REFERENCE]['photons']\n",
|
||||
"print(f\"{'variant':16s} {'QE rel':>8} {'MTF(200)':>9} {'DQE rel':>9} (relative to {REFERENCE})\")\n",
|
||||
"relative_dqe = {}\n",
|
||||
"for name, r in results.items():\n",
|
||||
" qe = r['photons'] / reference_photons\n",
|
||||
" mtf200 = r['mtf200_lsf'] # measured from the LSF, as in the poly notebook\n",
|
||||
" relative_dqe[name] = qe * mtf200**2\n",
|
||||
" print(f'{name:16s} {qe:8.3f} {mtf200:9.3f} {relative_dqe[name]:9.3f}')\n",
|
||||
"best = max(relative_dqe, key=relative_dqe.get)\n",
|
||||
"print(f\"\\nhighest relative DQE at {FREQUENCY:.0f} lp/mm: {best} \"\n",
|
||||
" f\"({relative_dqe[best]/relative_dqe['eta']:.2f}x eta)\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "28adb593",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 5. Summary"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "ff568b19",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:07.247817Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:07.247707Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:07.351773Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:07.351532Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{\n",
|
||||
" \"eta\": {\n",
|
||||
" \"sigma_um\": 1.5064047956840743,\n",
|
||||
" \"sigma_err_um\": 0.02338135508989506,\n",
|
||||
" \"mtf50_lsf_lpmm\": 130.01783547238728,\n",
|
||||
" \"mtf200_lsf\": 0.21821247141503744,\n",
|
||||
" \"chi2_ndf\": 1.831632850088404,\n",
|
||||
" \"mtf50_lpmm\": 124.39592974355975,\n",
|
||||
" \"mtf10_lpmm\": 226.7259781499331,\n",
|
||||
" \"rows_kept\": 0.9956521739130435,\n",
|
||||
" \"photons\": 230851827.0\n",
|
||||
" },\n",
|
||||
" \"GridBased flat\": {\n",
|
||||
" \"sigma_um\": 1.388201297480562,\n",
|
||||
" \"sigma_err_um\": 0.020239692729912443,\n",
|
||||
" \"mtf50_lsf_lpmm\": 141.25277630731097,\n",
|
||||
" \"mtf200_lsf\": 0.2506173773815928,\n",
|
||||
" \"chi2_ndf\": 1.8199081902180196,\n",
|
||||
" \"mtf50_lpmm\": 134.98807807583214,\n",
|
||||
" \"mtf10_lpmm\": 246.03139430216834,\n",
|
||||
" \"rows_kept\": 1.0,\n",
|
||||
" \"photons\": 566973421.0\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"written to /mnt/sls_det_storage/moench_data/MLXID/InferenceResults/GridBased/Edge_1filters_12keV/knife_edge_comparison.json\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"summary = {\n",
|
||||
" 'measurement': 'Edge/Flat_1filters_12keV',\n",
|
||||
" 'occupancy_percent': occupancy * 100, # flat field, ESF ROI\n",
|
||||
" 'roi_superpixel': list(ROI),\n",
|
||||
" 'bin_um': BIN_UM,\n",
|
||||
" 'bin_width_um': BIN_WIDTH_UM,\n",
|
||||
" 'convention': 'sigma = ODR p2 (Gaussian LSF); MTF50 = 1000 sqrt(ln 2 / 2) / (pi sigma); '\n",
|
||||
" 'ESF from DeepLearning/src, bin width 0.3 um',\n",
|
||||
" 'grid_model_epoch': grid_summary['epoch'],\n",
|
||||
" 'grid_frames': grid_summary['n_frames'],\n",
|
||||
" 'grid_subpixel_before': grid_summary['subpixel_nonuniformity_before'],\n",
|
||||
" 'grid_subpixel_after': grid_summary['subpixel_nonuniformity_after'],\n",
|
||||
" 'variants': {name: dict(sigma_um=float(r['sigma']), sigma_err_um=float(r['sigma_err']),\n",
|
||||
" mtf50_lsf_lpmm=float(r['mtf50_lsf']),\n",
|
||||
" mtf200_lsf=float(r['mtf200_lsf']),\n",
|
||||
" chi2_ndf=float(r['chi2_ndf']),\n",
|
||||
" mtf50_lpmm=float(r['mtf50']), mtf10_lpmm=float(r['mtf10']),\n",
|
||||
" rows_kept=float(r['rows_kept']), photons=float(r['photons']))\n",
|
||||
" for name, r in results.items()},\n",
|
||||
" 'relative_dqe_200lpmm': relative_dqe,\n",
|
||||
"}\n",
|
||||
"print(json.dumps(summary['variants'], indent=1))\n",
|
||||
"out = GRID / EDGE_RUN / 'knife_edge_comparison.json'\n",
|
||||
"json.dump(summary, open(out, 'w'), indent=1)\n",
|
||||
"print(f'\\nwritten to {out}')"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "pytorch_nightly",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.18"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,625 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "06536dc1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Knife edge, 2 filters — GridBased against the published chains\n",
|
||||
"\n",
|
||||
"Same measurement, same ROI, same ESF construction and same erf fit as\n",
|
||||
"`DeepLearning/Notebooks/KnifeEdge_2filters.ipynb`, so the only thing that\n",
|
||||
"differs between the rows of the final table is the reconstruction itself.\n",
|
||||
"The flat field sits at **1.81 % occupancy** inside the ESF ROI, 2.4x the 3-filter point.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**Edge width (revised 2026-09-28).** The ESF is binned and fitted exactly as\n",
|
||||
"`Plotting/fig_knife_edge.py --fit odr` does it: `generate_presampled_esf()` and\n",
|
||||
"`get_odr_fitting()` from `DeepLearning/src/funcs_postprocess.py` (bin content\n",
|
||||
"Σk/Σf), symmetric ±4σ window, **ESF bin width 0.3 µm**. The ODR model is\n",
|
||||
"`p0/2 (1 + erf((x - p1)/(sqrt(2) sigma))) + p3`, so the fit gives **sigma**, the\n",
|
||||
"width of the Gaussian LSF, which is what the tables quote, with\n",
|
||||
"`MTF50 [lp/mm] = 1000 sqrt(ln 2 / 2) / (pi sigma)`; MTF50 and MTF(200 lp/mm) are\n",
|
||||
"also measured from the LSF (`Plotting/knife_edge_numbers.py`: first crossing,\n",
|
||||
"central-difference correction), and the relative DQE uses the latter. Only the\n",
|
||||
"flattened GridBased reconstruction is analysed. Same processing as\n",
|
||||
"`KnifeEdge_poly2to20keV_Moench040.ipynb`.\n",
|
||||
"\n",
|
||||
"**Occupancy** is that of the flat field inside the ESF ROI: the reconstructed\n",
|
||||
"photons per 25 µm pixel per frame over `ROI // 10` (x 33–46, y 26–49 of the\n",
|
||||
"99 × 99 frame), the pixels over which `DeepLearning/Notebooks/KnifeEdge_3filters_pos0.ipynb`\n",
|
||||
"sums the deposited energy (0.705 % at 3 filters from the energy, 0.747 % here\n",
|
||||
"from the photons of the 12 keV model).\n",
|
||||
"\n",
|
||||
"*Until 2026-09-28 this notebook took the fitted sigma for sqrt(2) sigma (so its\n",
|
||||
"MTF50 was sqrt(2) too high), used 0.5 µm bins, and binned the ESF with an older\n",
|
||||
"copy of `generate_presampled_esf` (inverse-variance mean of k/f, biased low in\n",
|
||||
"the toe, sigma ~3 % too small). The previous version is in\n",
|
||||
"`Backup_260928_pre_sigma_fix/`.*\n",
|
||||
"\n",
|
||||
"The ROI, the oversampled ESF and the erf fit are the ones from\n",
|
||||
"`DeepLearning/Notebooks/KnifeEdge_3filters_pos0.ipynb`; the edge sits at the\n",
|
||||
"same place at all three flux points, so the same ROI holds throughout and the\n",
|
||||
"three notebooks are directly comparable.\n",
|
||||
"\n",
|
||||
"Run in the `pytorch_nightly` environment (ROOT + scipy + jupyter)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "338eb757",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:56.593670Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:56.593588Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:58.252767Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:58.252376Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Welcome to JupyROOT 6.28/10\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import json\n",
|
||||
"import sys\n",
|
||||
"from pathlib import Path\n",
|
||||
"\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"REPO = Path('/home/xie_x1/MLXID/GridBased')\n",
|
||||
"sys.path.insert(0, '/home/xie_x1/MLXID/DeepLearning/src') # the code Plotting/ uses\n",
|
||||
"sys.path.insert(0, '/home/xie_x1/MLXID/Plotting')\n",
|
||||
"from ROOT import TCanvas, gROOT\n",
|
||||
"gROOT.SetBatch(True)\n",
|
||||
"from funcs_postprocess import generate_presampled_esf, get_odr_fitting\n",
|
||||
"from knife_edge_numbers import mtf as mtf_from_lsf # first crossing, sinc-corrected\n",
|
||||
"\n",
|
||||
"GRID = Path('/mnt/sls_det_storage/moench_data/MLXID/InferenceResults/GridBased')\n",
|
||||
"PUBLISHED = Path('/home/xie_x1/MLXID/DeepLearning/InferenceResults')\n",
|
||||
"ETA = Path('/home/xie_x1/MLXID/EtaInterpolation/Results')\n",
|
||||
"\n",
|
||||
"EDGE_RUN, FLAT_RUN = 'Edge_2filters_12keV', 'Flat_2filters_12keV'\n",
|
||||
"BIN_UM = 2.5 # super-pixel = 25 um / 10\n",
|
||||
"ROI = (330, 465, 260, 490) # x1, x2, y1, y2, as published\n",
|
||||
"CROP = slice(10, -10) # 1010 -> 990, as published\n",
|
||||
"BIN_WIDTH_UM = 0.3 # presampled ESF bin, as Plotting/ and the manuscript\n",
|
||||
"\n",
|
||||
"plt.rcParams.update({'figure.dpi': 110, 'image.cmap': 'gray',\n",
|
||||
" 'image.origin': 'lower', 'image.interpolation': 'nearest'})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "bdc32295",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1. Load every reconstruction of the same measurement"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "c09dbe26",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:58.254687Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:58.254484Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:58.475103Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:58.474753Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"GridBased model epoch 135, 7,000,000 frames, occupancy 1.808 % (flat field, ESF ROI)\n",
|
||||
" sub-pixel excess rms 21.6 % -> 3.8 % after flattening\n",
|
||||
"\n",
|
||||
"variant edge photons flat photons relative\n",
|
||||
"eta 1.5670e+08 2.7062e+08 0.710\n",
|
||||
"cluster 1ph 1.5670e+08 2.7062e+08 0.710\n",
|
||||
"cluster <=2ph 2.0504e+08 3.5599e+08 0.929\n",
|
||||
"cluster <=3ph 2.2076e+08 3.8444e+08 1.000\n",
|
||||
"GridBased flat 2.3053e+08 4.0162e+08 1.044\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def crop(image):\n",
|
||||
" \"\"\"The published frames are cropped by 10 super-pixels on each side.\"\"\"\n",
|
||||
" return image[CROP, CROP] if image.shape[0] == 1010 else image\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"for run in (EDGE_RUN, FLAT_RUN):\n",
|
||||
" if not (GRID / run / 'summary.json').exists():\n",
|
||||
" raise SystemExit(\n",
|
||||
" f'{run} has not been reconstructed yet. Run:\\n'\n",
|
||||
" f' python scripts/05_infer_measurement.py '\n",
|
||||
" f'--config Configs/infer_measurement_12keV.yaml --run {run}')\n",
|
||||
"\n",
|
||||
"grid_summary = json.load(open(GRID / EDGE_RUN / 'summary.json'))\n",
|
||||
"flat_summary = json.load(open(GRID / FLAT_RUN / 'summary.json'))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def grid_image(run, flattened):\n",
|
||||
" name = 'binned_image_flattened.npy' if flattened else 'binned_image.npy'\n",
|
||||
" return np.load(GRID / run / name).astype(float)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"variants = {\n",
|
||||
" 'eta': (np.load(ETA / '2603MaxIV_Edge2Filters_12keV_fromClusters.npy'),\n",
|
||||
" np.load(ETA / '2603MaxIV_Flat2Filters_12keV_fromClusters.npy')),\n",
|
||||
" 'GridBased flat': (grid_image(EDGE_RUN, True), grid_image(FLAT_RUN, True)),\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"EXPERIMENT = {1: '1ph_260512_12keV_v260511_06',\n",
|
||||
" 2: '2ph_260610_12keV_v260610_01',\n",
|
||||
" 3: '3ph_260611_12keV_v260611_00'}\n",
|
||||
"KNIFE, FLAT = 'KnifeEdge_2filters', 'FlatField_2filters'\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def published_frame(run, n_photons):\n",
|
||||
" name = f'{n_photons}Photon_ML_superFrame_etaInterpolated.npy'\n",
|
||||
" return np.load(PUBLISHED / run / EXPERIMENT[n_photons] / 'augX1' / name).astype(float)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"cluster_edge = {n: published_frame(KNIFE, n) for n in (1, 2, 3)}\n",
|
||||
"cluster_flat = {n: published_frame(FLAT, n) for n in (1, 2, 3)}\n",
|
||||
"variants.update({\n",
|
||||
" 'cluster 1ph': (cluster_edge[1], cluster_flat[1]),\n",
|
||||
" 'cluster <=2ph': (cluster_edge[1] + cluster_edge[2], cluster_flat[1] + cluster_flat[2]),\n",
|
||||
" 'cluster <=3ph': (cluster_edge[1] + cluster_edge[2] + cluster_edge[3],\n",
|
||||
" cluster_flat[1] + cluster_flat[2] + cluster_flat[3]),\n",
|
||||
"})\n",
|
||||
"\n",
|
||||
"ORDER = ['eta', 'cluster 1ph', 'cluster <=2ph', 'cluster <=3ph', 'GridBased flat']\n",
|
||||
"variants = {name: (crop(e), crop(f)) for name, (e, f) in variants.items()}\n",
|
||||
"variants = {name: variants[name] for name in ORDER}\n",
|
||||
"\n",
|
||||
"def flat_occupancy(run):\n",
|
||||
" # reconstructed photons per 25 um pixel per frame in the flat field, inside the\n",
|
||||
" # ESF ROI: ROI // 10 in pixels of the 99 x 99 frame, both ends included as in\n",
|
||||
" # DeepLearning/Notebooks; +1 because the 101 x 101 frame is cropped by 1 px\n",
|
||||
" summary = json.load(open(GRID / run / 'summary.json'))\n",
|
||||
" native = np.load(GRID / run / 'native_image.npy') / summary['n_frames']\n",
|
||||
" x0, x1, y0, y1 = (v // 10 for v in ROI)\n",
|
||||
" return float(native[y0 + 1:y1 + 2, x0 + 1:x1 + 2].mean())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"occupancy = flat_occupancy(FLAT_RUN)\n",
|
||||
"print(f\"GridBased model epoch {grid_summary['epoch']}, \"\n",
|
||||
" f\"{grid_summary['n_frames']:,} frames, \"\n",
|
||||
" f\"occupancy {occupancy*100:.3f} % (flat field, ESF ROI)\")\n",
|
||||
"print(f\" sub-pixel excess rms {grid_summary['subpixel_nonuniformity_before']*100:.1f} % -> \"\n",
|
||||
" f\"{grid_summary['subpixel_nonuniformity_after']*100:.1f} % after flattening\\n\")\n",
|
||||
"print(f\"{'variant':16s} {'edge photons':>14} {'flat photons':>14} relative\")\n",
|
||||
"reference = variants['cluster <=3ph'][0].sum()\n",
|
||||
"for name, (e, f) in variants.items():\n",
|
||||
" print(f'{name:16s} {e.sum():14.4e} {f.sum():14.4e} {e.sum()/reference:8.3f}')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "8c5580a3",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:58.476333Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:58.476173Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:58.963183Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:58.962866Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAABmcAAAH2CAYAAACFuVjoAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AAEAAElEQVR4nOy9eZgU1dn+f3fP1j29zcIwsiijEAXiIOIrKi4gogRQwSUi0ShqgrjGBRNDVDA/jSGuib6uKO6CGiUquIu+cYl+TYxRIa64oQI6W89Mz16/P7juM0+dqe7p2WF4Ptc1FzPV1VWnTjX93PVsx+c4jgNFURRFURRFURRFURRFURRFURSlV/D39QAURVEURVEURVEURVEURVEURVG2JzQ4oyiKoiiKoiiKoiiKoiiKoiiK0otocEZRFEVRFEVRFEVRFEVRFEVRFKUX0eCMoiiKoiiKoiiKoiiKoiiKoihKL6LBGUVRFEVRFEVRFEVRFEVRFEVRlF5EgzOKoiiKoiiKoiiKoiiKoiiKoii9iAZnFEVRFEVRFEVRFEVRFEVRFEVRehENziiKoiiKoiiKoiiKoiiKoiiKovQiGpxRFEVRFEVRFEVRFEVRFEVRFEXpRTQ4oyiKoiiKoiiKoiiKoiiKoiiK0otocEZRFEVRFGU75u6774bP58PLL7/crcd9+eWX4fP5cPfdd7u219bW4txzz8VOO+2EjIwMlJSUdOt5u4NJkyZtlePqKsnuSSp8Ph/mzp3bY2Pqqc9fXzF37lz4fL609y8pKcGkSZNc2zr7+evM/e0O+uv/F0VRFEVRFEXpaTQ4oyiKoiiKovQaS5YswY033ojZs2fj7rvvxg033NDXQ9quqaiowOLFi3s0OPLyyy9j8eLFqKio6LFzKNsGJSUl8Pl8SX8WL17s2v/zzz/HGWecgVGjRiEUCiEvLw+77rorjj/+eDz22GOufSdNmpT0uCNGjGh3bIsXL3a9x+/3Iy8vDwceeCDuu+++lO999tlncdRRR2HQoEHIzs5GUVERpk6diuXLl8NxnKTnevXVV9ufNEVRFEVRFKXfktnXA1AURVEURVH6HwcddBASiQSysrJc259//nmUlpbi6quv7qORbb943ZOKigpcfvnlANCmgqO7ePnll3H55Zdj7ty5yMvL65Fz9Ceee+45T4d+f6G4uBjXXHON52tjxowxv//rX//CQQcdhObmZpxwwgk4++yzAQCffPIJVq1aherqahx99NGu9/v9ftxzzz1tjhuJRNIe36WXXopdd90Vzc3N+PLLL7F06VKcdNJJ2LBhAy6++GLXvi0tLZg/fz7uuOMODB8+HPPmzcOwYcOwceNGPPLII5gzZw4efPBBrFixAsFgMO0xKIqiKIqiKNsHGpxRFEVRFEVRuh2/349AINBm+3fffYeddtqpD0akJLsnytZFdnZ2Xw+hRwmHwzjxxBPb3W/x4sWoqanBypUrMXPmTNdr119/Pb7++us27/H5fGkdOxWHHXYYDjjgAPP3qaeeil133RVLlizBRRddhIyMDPPaFVdcgTvuuAPHHHMMHnjgAeTk5JjXLr74YixYsADXXXcdzj77bNx5551dGpeiKIqiKIrS/9C2ZoqiKIqiKEobbrnlFmRmZuK4445DfX09gNb1MT766CPMnDkTsVgM4XAYM2bMwKeffup6v73+Bdv4rF+/Hq+88opnG6N33nkHxx57LAYOHIjs7GzssssuuPjii1FbW5v2uD/99FPMnTsXgwcPRnZ2NoYOHYozzzwT33//fZt9P/nkExx11FGIxWKIRCI47LDD8O677yY99n333YcxY8YgJycHQ4cOxa9//WusW7fOsx2T4zi44447MH78eIRCIYRCIUyYMAErV65M+1psNmzYAJ/PhwsvvNC1fd68efD5fDj99NNd2y+44AL4fD5s3LgRQNt7cvfdd2PnnXcGAFx++eXmnnitH/LWW29h8uTJCIfDyMvLw5w5c7B58+Z2xzxp0iRTmbPzzjsnbV/lOA5uuOEG7LrrrsjJycEuu+yC66+/3vOYXf2ccI2UL774Ascccwzy8/MRCoVw6KGH4t///rdr31TruPAz/fnnn7d57YcffsCpp56KoqIiBINBTJgwAS+99FKHxidZt24d5syZgx133BE5OTkYOHAg9t9/fyxbtszzGPysBgIBDBkyBL/73e/Q3NzcZr+e/P/SVT766CMAwCGHHOL5+tChQ3vs3JIhQ4Zg1KhRqKiocH3mv//+e/zxj3/EkCFDcM8997gCM8CWQNHVV1+NvfbaC8uWLcMHH3zQK+NVFEVRFEVRth20ckZRFEVRFEUxOI6D3/72t1iyZAnOP/98XHvtta4Fzjds2ICDDjoIRx55JJYsWYKPP/4YN954I4488ki899578Pu9c3+OPvpojBgxAueffz4GDBiA3/3udwBa2xg988wzmDVrFnbccUecc845KC4uxrvvvovrrrsOr732GtasWYPMzNTS9d///jcmTZqE3NxcnHrqqRg2bBg+/vhj3HLLLXjxxRfx1ltvIRaLAQC++uorTJgwARUVFZg/fz5GjRqFN954A5MmTUJhYWGbY//v//4vzj77bIwcORKXX345srKy8NBDDyVdq+WUU07Bvffei5kzZ+KEE04AADz22GM46qijcMstt2D+/Pmpb4QHQ4YMwciRI/HCCy+4tr/44ovw+/2e23fffXcUFxd7Hu+ggw7C9ddfj/PPPx9HHXWUaREVDodd+7377ruYNm0aTjrpJMyePRv//Oc/sXTpUpSXl+OZZ55JOebf/e53KCgowOOPP47rr78eAwYMAOBuXwUACxcuRFVVFU455RSEw2Hce++9uOCCCzBo0CAcf/zxZr/u+JwAQE1NDSZOnIg999wTV1xxBb766iv87//+Lw488EC88cYb2H333ds9RiqmTp2KaDSKSy+9FGVlZbj11lsxdepUPP3005gyZUqHjvXDDz/g4IMPRktLC04//XTsvPPOKC8vx3vvvYdXXnkFp5xyimv/2267DRs2bMAvfvELFBUV4bHHHsMf/vAHRCIRV1uunvz/koqWlhbP4A8A5OXlmfs3fPhwfPjhh1i6dCl+9atfub6HUuF17Fgs1qbFYro0NDTgq6++MmvQkFWrViGRSODnP/85QqGQ53v9fj/mzZuH008/HX/961/x4x//uFNjUBRFURRFUfopjqIoiqIoirLdsmzZMgeAs2bNGqeurs45/vjjHb/f7/z5z39us++wYcMcAM6DDz7o2n7VVVc5AJxnn33WbFuzZo0DwFm2bFmbY0ycONG1LZFIODvssIMzfvx4p66uzvXaI4884gBw7r777navZezYsc7OO+/s/PDDD67t//jHPxy/3+8sXrzYbPv5z3/uAHAef/xxz2sZNmyY2VZeXu6EQiFnl112caqqqsz2uro6Z++993YAOIsWLTLbV65c6QBwrrvuujZjPPzww51oNOo6Tkc466yzHJ/P52zcuNFxHMdZv369A8Bcz2effeY4juNs2rTJ8fl8zq9+9SvzXq97wvfL8UsAOD6fz3n11Vdd208//XQHgPPhhx+2O+ZFixY5AJz169e3eY2fvzFjxrjufXV1tVNYWOjst99+Zlt3fU4mTpzoAHDOOuss1/Y333zT8fl8ziGHHGK2JfscJ7uuk08+2QHgHHHEEU5zc7PZ/vnnnzu5ubnOj370I6elpcVs9/r/MHHiRNfn729/+5sDwFm+fHnK6+JYd9hhB6esrMxsb25udkaNGuUMGjTItX9P/X9JBb9Dkv38/e9/d40jOzvbAeDstNNOzkknneTceOONzr///W/PY/O+ev08/fTT7Y6N9/Opp55yNm/e7GzcuNF56623nKOOOsoB4Bx//PGu/S+88EIHgPPXv/415XHffvttB4BzzDHHtDmXvF5FURRFURRl+0PbmimKoiiKoigoLy/HYYcdhpUrV+KRRx7Bueee67nf4MGDMWfOHNe2Qw89FEBrG6KO8sILL+C7777D3LlzEY/H8f3335ufiRMnIhQK4dlnn015jPfffx///ve/cfzxx5vMfP4MHz4cP/rRj8wxWlpasHLlSowePRqzZs1yHee8885rUzny3HPPoaamBmeeeaZrYfGcnBycf/75bcZy3333IRgMYvbs2a5xfP/99zjqqKNQVVWFN954o1Nzdcghh8BxHNMi68UXX0RGRgYuv/xyZGRk4MUXXwQAvPTSS3AcJ2lLqI6w3377Yf/993dt6+o9tzn77LNdbaFCoRD2228/1/G743MiWbhwoevv8ePHY8qUKXjppZdQXl7epev57W9/66oiGzZsGE444QR8/PHH+M9//tOhY7FaY/Xq1aisrGx3/1NPPRX5+fnmb7/fj0MOOQTffvstqqurAfTs/5f2GDx4MJ5//nnPn9LSUrPfPvvsg3/961847bTT0NTUhHvvvRfnnHMOxo4di3HjxrVpQcdr9Tru3nvvnfb4Dj/8cBQVFaG4uBjjx4/HE088gTPOOKPNmjG8F6wuSgZfT+feKYqiKIqiKNsX2tZMURRFURRFwdy5c1FVVYXnn38+ZdulXXbZpc02tjX64YcfOnXudevWAQDOPPNMnHnmmZ77cN2U9o5x1VVX4aqrrvLch2PftGkT4vE4Ro8e3WafQCCA4cOHo6Kiwmz77LPPAAAjR45ss/+oUaM8x5JIJDBkyJCk423vepJx8MEHmxZmxx9/PF544QXstdde2HnnnTFu3Di88MIL+MUvfoEXXngBGRkZmDhxYqfOI+mJe57uOeTxu+NzQvLy8jB48OA220ePHo3nn38en332Gfbaa6+0juWF12eL2z755BPsscceaR/roIMOwqmnnoq77roLDz30EPbaay9MmDABxx57LPbbb782+7d3v8LhcI/+f2mPYDCYdmu3H//4x1i6dCkA4Ouvv8Zrr72Ge++9F6tXr8b06dPxwQcfuAJLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1650x506 with 6 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"fig, axes = plt.subplots(1, len(ORDER) if len(ORDER) < 4 else 3, figsize=(15, 4.6))\n",
|
||||
"extent = [0, 990 * BIN_UM, 0, 990 * BIN_UM]\n",
|
||||
"shown = ORDER if len(ORDER) < 4 else ['eta', 'cluster <=3ph', 'GridBased flat']\n",
|
||||
"for ax, name in zip(np.atleast_1d(axes), shown):\n",
|
||||
" image = variants[name][0]\n",
|
||||
" im = ax.imshow(image, extent=extent, vmax=np.percentile(image, 99.5))\n",
|
||||
" ax.add_patch(plt.Rectangle((ROI[0]*BIN_UM, ROI[2]*BIN_UM),\n",
|
||||
" (ROI[1]-ROI[0])*BIN_UM, (ROI[3]-ROI[2])*BIN_UM,\n",
|
||||
" edgecolor='red', facecolor='none', lw=1.4))\n",
|
||||
" ax.set_title(name); ax.set_xlabel('x [um]'); ax.set_ylabel('y [um]')\n",
|
||||
" plt.colorbar(im, ax=ax, fraction=0.046)\n",
|
||||
"fig.suptitle('knife edge, with the published ESF ROI')\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "1e889d01",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2. Edge spread function\n",
|
||||
"\n",
|
||||
"`generate_presampled_esf` fits an erf to every row of the ROI, fits a straight\n",
|
||||
"line through the edge positions, and re-samples the ROI onto a common axis;\n",
|
||||
"`get_odr_fitting` then fits the erf with x and y errors inside |x - p1| <= 4 sigma\n",
|
||||
"(the fit of `Plotting/fig_knife_edge.py --fit odr`)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "e36d7502",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:58.964776Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:58.964610Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:00.677476Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:00.677078Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Final Edge Midpoint Fit: slope = -0.0858, intercept = 432.3990, chi2/ndf = 0.0751\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0854, intercept = 432.2740, chi2/ndf = 0.0576\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0855, intercept = 432.4402, chi2/ndf = 0.0479\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0850, intercept = 432.2537, chi2/ndf = 0.0406\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0858, intercept = 432.5887, chi2/ndf = 0.0361\n",
|
||||
"variant sigma [um] chi2/ndf MTF50 MTF50 LSF MTF(200) LSF rows\n",
|
||||
"eta 1.483 +- 0.024 1.61 126.4 131.7 0.187 100%\n",
|
||||
"cluster 1ph 1.352 +- 0.022 1.44 138.6 144.8 0.229 100%\n",
|
||||
"cluster <=2ph 1.372 +- 0.022 1.50 136.5 142.7 0.223 100%\n",
|
||||
"cluster <=3ph 1.386 +- 0.018 1.02 135.2 139.7 0.244 100%\n",
|
||||
"GridBased flat 1.346 +- 0.019 1.15 139.2 143.8 0.259 100%\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def analyse(edge_image, flat_image, label):\n",
|
||||
" esf = generate_presampled_esf(edge_image, flat_image, ROI,\n",
|
||||
" pixel_size_um=BIN_UM, bin_width_um=BIN_WIDTH_UM,\n",
|
||||
" chi2_threshold=15.0, residual_tolerance_px=1.0)\n",
|
||||
" x, z = esf['numpy']['x'], esf['numpy']['z']\n",
|
||||
" odr = get_odr_fitting(x, z, esf['numpy']['x_err'], esf['numpy']['z_err'], n_sigma=4.0)\n",
|
||||
" sigma, sigma_err = odr['sigma_um'], odr['sigma_err_um'] # sigma of the Gaussian LSF\n",
|
||||
" try:\n",
|
||||
" mtf50_lsf, mtf200_lsf = mtf_from_lsf(dict(x=x, z=z, pars=odr['beta']))\n",
|
||||
" except Exception:\n",
|
||||
" mtf50_lsf = mtf200_lsf = np.nan\n",
|
||||
" n_fit = int(odr['mask'].sum())\n",
|
||||
" ndf = max(n_fit - len(odr['beta']), 1)\n",
|
||||
" x_fit = x[odr['mask']]\n",
|
||||
" return dict(label=label, x=x, z=z, sigma=sigma, sigma_err=sigma_err, sigma_gauss=sigma,\n",
|
||||
" chi2_ndf=odr['chi2_ndf'], chi2=odr['chi2_ndf'] * ndf, ndf=ndf,\n",
|
||||
" mtf50=1000 * np.sqrt(np.log(2) / 2) / (np.pi * sigma),\n",
|
||||
" mtf10=1000 * np.sqrt(np.log(10) / 2) / (np.pi * sigma),\n",
|
||||
" mtf50_lsf=mtf50_lsf, mtf200_lsf=mtf200_lsf,\n",
|
||||
" rows_kept=esf['valid_lines_ratio'],\n",
|
||||
" edge_slope=esf['edge_slope'], edge_centre=odr['beta'][1],\n",
|
||||
" fit_points=n_fit, fit_range=(x_fit.min(), x_fit.max()),\n",
|
||||
" photons=float(edge_image.sum()), odr=odr)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"results = {name: analyse(edge, flat, name) for name, (edge, flat) in variants.items()}\n",
|
||||
"\n",
|
||||
"print(f\"{'variant':16s} {'sigma [um]':>16} {'chi2/ndf':>9} {'MTF50':>7} {'MTF50 LSF':>9} \"\n",
|
||||
" f\"{'MTF(200) LSF':>12} {'rows':>6}\")\n",
|
||||
"for name, r in results.items():\n",
|
||||
" print(f\"{name:16s} {r['sigma']:7.3f} +- {r['sigma_err']:.3f} {r['chi2_ndf']:9.2f} {r['mtf50']:7.1f} \"\n",
|
||||
" f\"{r['mtf50_lsf']:9.1f} {r['mtf200_lsf']:12.3f} {r['rows_kept']*100:5.0f}%\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "55ce79f2",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:00.678708Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:00.678621Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:01.069086Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:01.068788Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1375x528 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"COLOURS = {'eta': '#a0451c', 'cluster 1ph': '#6b6b6b', 'cluster <=2ph': '#7b5aa6',\n",
|
||||
" 'cluster <=3ph': '#4b2a6b', 'GridBased raw': '#4cbcac', 'GridBased flat': '#10695f'}\n",
|
||||
"frequency = np.linspace(0, 400, 2000)\n",
|
||||
"fig, ax = plt.subplots(1, 2, figsize=(12.5, 4.8))\n",
|
||||
"for name, r in results.items():\n",
|
||||
" ax[0].plot(r['x'], r['z'], lw=1.1, color=COLOURS[name],\n",
|
||||
" label=f\"{name}: $\\\\sigma$ = {r['sigma']:.3f} $\\\\pm$ {r['sigma_err']:.3f} $\\\\mu$m\")\n",
|
||||
" sigma_mm = r['sigma_gauss'] / 1000.0\n",
|
||||
" ax[1].plot(frequency, np.exp(-2 * np.pi**2 * sigma_mm**2 * frequency**2),\n",
|
||||
" lw=1.6, color=COLOURS[name], label=f\"{name} ({r['mtf50']:.0f} lp/mm)\")\n",
|
||||
"ax[0].set_xlim(-9, 9); ax[0].set_ylim(-0.05, 1.35)\n",
|
||||
"ax[0].set_xlabel(r'position across the edge [$\\mu$m]')\n",
|
||||
"ax[0].set_ylabel('relative intensity')\n",
|
||||
"ax[0].legend(fontsize=8); ax[0].grid(alpha=.3); ax[0].set_title('oversampled ESF')\n",
|
||||
"ax[1].axvline(200, color='k', ls=':', lw=.8, label='2.5 um Nyquist')\n",
|
||||
"ax[1].axhline(0.5, color='grey', lw=.5)\n",
|
||||
"ax[1].set_xlim(0, 400); ax[1].set_ylim(0, 1.05)\n",
|
||||
"ax[1].set_xlabel('spatial frequency [lp/mm]'); ax[1].set_ylabel('MTF')\n",
|
||||
"ax[1].legend(fontsize=8); ax[1].grid(alpha=.3); ax[1].set_title('MTF from the fitted ESF')\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6ff2c3c0",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3. Where the GridBased sub-pixel phase stands"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "30d4c001",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:01.070347Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:01.070263Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:01.586719Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:01.586384Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAABk4AAAHKCAYAAABFSbckAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AAEAAElEQVR4nOy9ebgdZZU1vmo6453nezMPhCQEHAG1VSZxQkT0QxBptNXPtp21GwRsBexu8OlGpAe62x4U9SfKoDafgoqtaKtgI/OQhJA5N7nzvecOZ6zp98fe+z2pJJBwM4e9nifPya1T9dY7VdU+9a61lxXHcQyFQqFQKBQKhUKhUCgUCoVCoVAoFAoF7MNdAYVCoVAoFAqFQqFQKBQKhUKhUCgUiiMFunCiUCgUCoVCoVAoFAqFQqFQKBQKhULB0IUThUKhUCgUCoVCoVAoFAqFQqFQKBQKhi6cKBQKhUKhUCgUCoVCoVAoFAqFQqFQMHThRKFQKBQKhUKhUCgUCoVCoVAoFAqFgqELJwqFQqFQKBQKhUKhUCgUCoVCoVAoFAxdOFEoFAqFQqFQKBQKhUKhUCgUCoVCoWDowolCoVAoFAqFQqFQKBQKhUKhUCgUCgVDF04UCoVCoVAoFAqFQqFQKBQKhUKhUCgYunCiUCgUCoVCoVAoFAqFQqFQKBQKhULB0IUTxUHHV7/6VcyfPx+O4+Ad73gHNm/eDMuycOedd76gcn71q1/huuuuOyzntSwLDz300PPud8MNN8CyrBdUNgBcc801aGhoeMHHPRceeeQRvOpVr0Iul4NlWSgUCges7BeKTZs24ayzzkJjYyMsy8Jjjz2G97///Vi1atULLuuaa67B/fffv8/bDyROP/10vO1tbzuo51AoFArF0QeNcQ4M9hQvHIrnu2BPsdNsnv2FQgHXXHMNVq9evU/bDzQWLlyIj3/84wf1HAqFQqFQKBQKxYsF7uGugOLYxtq1a/HZz34WV1xxBc4991x0dHTMuqxf/epXuOGGG3DVVVfN6ry9vb144IEHsGzZslnX4WjAxz72MYRhiLvvvhvZbBaNjY2HrS5XXXUVNm7ciDvvvBPNzc371ffXXnstGhoa8JrXvGafth9I/PM//zMcxzlo5SsUCoXi6IPGOAcOe4oXDsXzXXCgYqdCoYBrr70Wq1atwsqVK/e6/UDjhz/8IVpbWw9a+QqFQqFQKBQKxYsJunCiOKhYu3YtAOD//t//i8WLFwMANm/efFjOCwCvetWrDvq5DzfWrFmDT37ykzjjjDP2u6xKpYJMJrNfdXnd616HN73pTftdl8OJg/mSQ6FQKBRHJzTGOXA4FPHC88U0BzJ2Opx42ctedriroFAoFAqFQqFQHDPQVF2Kg4b3v//9OP/88wEAS5YsgWVZuOWWW/a477e+9S289rWvRVtbG1pbW3H66afjwQcfNN9fc801uPbaa1EsFmFZFizLwumnn/6CzvtcaSxuueUWnHTSSchkMpgzZw4+//nPIwiC523b1NQULr30UjQ2NqKzsxOXX375Xo/ZG/7whz/glFNOQSaTwYoVK/DjH/94t33uvvtunHrqqchms+js7MSf/dmfoVgsAqin25icnMRf/dVfJfooiiJcd911WLRoEdLpNI477jjcdNNNibIlZdiDDz6IV7/61chkMvjHf/xHAPRC4bzzzkNzczPy+TzOOeccbNiw4TnbIn39+OOP49vf/jYsy8LChQv3uO/AwAA+8IEPYPHixchmszjuuONw1VVXoVqtmn0kPchll11mxl/au6ftABDHMW644QYsW7YM6XQaixcvxle/+tU9tvmJJ57Aa1/7WuRyOaxatQo/+9nPEvvtmq5jX4+r1Wr45Cc/iba2NjQ3N+ODH/wgvvnNb8KyrEPyck2hUCgUBwca4+wb1q5di4suugjz5s1DLpfDypUr8ZWvfAVRFAF47njhQD3f9xTT7Izni51m05ZFixYBAC644AJT7+fbDgDVahVXXXUVFixYgHQ6jRUrVuDWW29NnFvSnP7qV7/Cy172MuTzeZxyyil4+OGHE/vtmqprX4+bnJzEJZdckhjzL3/5ywc1PZtCoVAoFAqFQnGkQxUnioOGL3zhCzj++ONx1VVX4Qc/+AF6e3uxZMkS86J/Z2zevBmXXnoplixZglqthltvvRWvf/3r8cQTT2DZsmX40Ic+hP7+ftx666345S9/CQBoamra7/PeeOONuPzyy/GZz3wGX/nKV7BmzRp8/vOfRxiG+PKXv/ycbfvABz6An/3sZ/jyl7+MRYsW4eabb8bjjz8+y54CfN/HhRdeiD//8z/HokWL8C//8i84//zz8eijjxo/kDvvvBMXXngh/uRP/gTXXnstBgYGcMUVV2BiYgLf+9738PKXvxwPPPAAzjzzTFx88cX40Ic+ZProsssuw0033YSrrroKr3vd6/Dzn/8cn/nMZzA9PY0vfOELph61Wg3vfe978ZnPfAbXX389WltbsXHjRrzmNa/BqlWrcMstt8C2bfzN3/wNzjrrLDzzzDNIp9O7tUdShrz3ve/F8uXL8YUvfGGP+wHA6Ogo2tracOONN6K1tRXr1q3DNddcg8HBQXz9618HADzwwAN49atfjU984hO4+OKLAZAK5Lm2A8CnPvUp/Md//Ac+//nP49RTT8X999+Pz33uc8hms/jIRz6S6PtLLrkEn/zkJ/GFL3wB119/Pd71rndhy5YtaG9vf94x29txV1xxBb72ta/hS1/6El760pfi9ttvx1/+5V/u26RQKBQKxRELjXH2Ddu3b8fxxx+P9773vWhsbMRjjz2Gq6++GsViEV/84hefM16oVqv7/XzfU0yzK54vdppNW37wgx/gne98J6677jqjXnm+7QDw7ne/G7/97W9x9dVXY8WKFbjnnntwySWXoLW1FW95y1vM+QcHB/HJT34SV1xxBZqamnDFFVfg/PPPx4YNG+B53nOOwb4c9yd/8if45S9/ib/927/FggUL8LWvfQ2PPPLIPo+zQqFQKBQKhUJxTCJWKA4i7rjjjhhAvGnTJrNt06ZNMYD4jjvu2OMxYRjGvu/Hxx9/fHzllVea7VdffXWcz+cP2HmnpqbihoaGxDniOI5vvvnmOJvNxqOjo3Ecx/F9990XA4j/8Ic/xHEcx6tXr44ty4r/8z//0xzj+348f/78eDaX1NVXXx0DSJQXBEG8cOHC+D3veU8cx3EcRVG8YMEC87fg7rvvji3Lip966imzLZ/Px1dffbX5e2RkJPY8L77ssssSx374wx+O8/l8PD09najH7bffntjv0ksvjRctWhSXy2WzbXh4OM7n8/HNN9/8vG074YQT4ve9732Jbe973/viE0444TmP8X0//s53vhO7rhsXi0WzHUD8d3/3d7vtv6ft69evjy3Lir/2ta8ltl922WVxT09PHIZhos1333232efZZ5+NAcTf/va3zbbTTjstPuecc8zf+3Lc2NhYnMlk4i996UuJOpx22mm7zU2FQqFQHH3QGOeFIYqi2Pf9+G/+5m/i3t7exHd7ihcOxPN915jmubBr7BTHuz/796UtzzX+z7X9l7/8ZQwg/tnPfpbYfsEFF8Qnn3yy+ft973vfbvHez3/+8xhA/Jvf/MZsW7BgQfyxj33sBR339NNPxwDib33rW2afIAjixYsX7/eYKxQKhUKhUCgURzM0VZfiiMCaNWtw/vnno7u7G47jwPM8PPPMM1i3bt1BO+f999+PmZkZXHDBBQiCwPw788wzUS6X8dRTT+3xuAcffBBxHJtUGQDgui7OO++8/arPzuU5joO3v/3t+P3vfw8AWLduHbZs2YJ3v/vdibqedtppsCwLDz300HOW+7//+79G0bIz3vOe96BYLOLRRx9NbH/rW9+a+Pvee+/FeeedB9d1zXlbW1vxkpe8BH/4wx/2q80Apdy46aabsHLlSmSzWXieh/e+970IggAbN26cVZn//d//DQB417veleivs846C4ODg9i2bZvZ17ZtvOENbzB/L126FKlUCv39/c97jr0d9+STT6JSqeDtb3974rj9nScKhUKhOLrwYo5xKpUKrr76aixduhTpdBqe5+Hzn/88BgYGMDMz84LLeyHPd2D3mGZ/cKDbAlCM1dbWhjPPPHO39jz66KMIw9Ds29fXhxNOOMH8LQqcvcUreztOYrmd4xXHcRIpShUKhUKhUCgUihcjNFWX4rBjenoab3zjG9HZ2Ykbb7wRCxYsQCaTwYc+9CFUKpWDdt7R0VEAlKZhT9j1x7dgYGAAnuftlvKhu7t71nXZU3ldXV0YGBhI1HXnFxn7UlcAmJiYAAD09PQktsvf4+PjZlsul0M+n0/sNzo6iptuumk3TxQAyGazz3nefcVNN92Ev/iLv8Dll1+OM844A62trfjDH/6Aj33sY7Me/9HRUcRxjI6Ojj1+v23bNixYsAAAtSGVSiW+9zxvr+fe23Eydp2dnYl9urq69r0hCoVCoTiq8WKPcT73uc/h3//933H11VfjFa94BVpaWnDXXXfhr//6r1GpVNDQ0PCCynshz/c9xTT7gwPdFoDaMz4+/pyptgYGBjB37lwAQEtLS+I7iUH2No/2dpyMeXNzc2I/jVcUCoVCoVAoFC926MKJ4rDjgQceQH9/P3784x/jJS95idk+OTlpfiweDLS1tQEAfvCDH2DevHm7fS9Gnruit7cXvu9jYmIi8WJhaGho1nXZU3nDw8Mm/7XU9Z/+6Z9w6qmn7nZ8X1/fc5Ytxw4NDWHOnDlm++DgYOJ7AHs0AW1ra8M555yDj370o7t919jY+Lzt2hfccccdePvb347rr7/ebFu9evV+ldnW1gbLsvDb3/52t8UNADj++OP3q/x9gYzdyMhIYnyGh4cP+rkVCoVCcWTgxR7j3HHHHfjTP/1TfO5znzPb7r777lmVBbyw5/uBNjY/0G0BqD2dnZ2455579vj9oVi8kDGLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1650x462 with 5 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"before = np.load(GRID / FLAT_RUN / 'subpixel_phase_before.npy')\n",
|
||||
"after = np.load(GRID / FLAT_RUN / 'subpixel_phase_after.npy')\n",
|
||||
"\n",
|
||||
"fig, axes = plt.subplots(1, 3, figsize=(15, 4.2))\n",
|
||||
"for ax, histogram, title in ((axes[0], before, 'before flattening'),\n",
|
||||
" (axes[1], after, 'after flattening')):\n",
|
||||
" im = ax.imshow(histogram.T / histogram.mean(), origin='lower', extent=[0, 1, 0, 1],\n",
|
||||
" vmin=0.9, vmax=1.1, cmap='viridis')\n",
|
||||
" ax.set_title(f'flat field, {title}', fontsize=10)\n",
|
||||
" ax.set_xlabel('sub-pixel x'); ax.set_ylabel('sub-pixel y')\n",
|
||||
" plt.colorbar(im, ax=ax, fraction=0.046)\n",
|
||||
"for histogram, title in ((before, 'before'), (after, 'after')):\n",
|
||||
" profile = histogram.sum(axis=1)\n",
|
||||
" axes[2].plot(np.linspace(0, 1, len(profile)), profile / profile.mean(), lw=1, label=title)\n",
|
||||
"axes[2].axhline(1, color='k', lw=.6); axes[2].set_xlabel('sub-pixel x')\n",
|
||||
"axes[2].set_ylabel('relative density'); axes[2].legend(); axes[2].grid(alpha=.3)\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9837906d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4. Relative DQE"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "460617ee",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:01.588078Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:01.587992Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:01.691826Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:01.691526Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"variant QE rel MTF(200) DQE rel (relative to cluster <=3ph)\n",
|
||||
"eta 0.710 0.187 0.025\n",
|
||||
"cluster 1ph 0.710 0.229 0.037\n",
|
||||
"cluster <=2ph 0.929 0.223 0.046\n",
|
||||
"cluster <=3ph 1.000 0.244 0.060\n",
|
||||
"GridBased flat 1.044 0.259 0.070\n",
|
||||
"\n",
|
||||
"highest relative DQE at 200 lp/mm: GridBased flat (2.82x eta)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# DQE(f) is proportional to QE * MTF(f)^2. Every chain sees the same beam, so\n",
|
||||
"# the ratio of detected photons is the ratio of QE and the relative DQE is well\n",
|
||||
"# defined even without the absolute incident flux.\n",
|
||||
"def mtf_at(frequency_lpmm, sigma_gauss_um):\n",
|
||||
" sigma_mm = sigma_gauss_um / 1000.0\n",
|
||||
" return float(np.exp(-2 * np.pi**2 * sigma_mm**2 * frequency_lpmm**2))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"FREQUENCY = 200.0 # lp/mm, the Nyquist of the 2.5 um bins\n",
|
||||
"REFERENCE = 'cluster <=3ph'\n",
|
||||
"reference_photons = results[REFERENCE]['photons']\n",
|
||||
"print(f\"{'variant':16s} {'QE rel':>8} {'MTF(200)':>9} {'DQE rel':>9} (relative to {REFERENCE})\")\n",
|
||||
"relative_dqe = {}\n",
|
||||
"for name, r in results.items():\n",
|
||||
" qe = r['photons'] / reference_photons\n",
|
||||
" mtf200 = r['mtf200_lsf'] # measured from the LSF, as in the poly notebook\n",
|
||||
" relative_dqe[name] = qe * mtf200**2\n",
|
||||
" print(f'{name:16s} {qe:8.3f} {mtf200:9.3f} {relative_dqe[name]:9.3f}')\n",
|
||||
"best = max(relative_dqe, key=relative_dqe.get)\n",
|
||||
"print(f\"\\nhighest relative DQE at {FREQUENCY:.0f} lp/mm: {best} \"\n",
|
||||
" f\"({relative_dqe[best]/relative_dqe['eta']:.2f}x eta)\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9d317fe5",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 5. Summary"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "764dbd8d",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:23:01.692963Z",
|
||||
"iopub.status.busy": "2026-09-28T08:23:01.692876Z",
|
||||
"iopub.status.idle": "2026-09-28T08:23:01.799221Z",
|
||||
"shell.execute_reply": "2026-09-28T08:23:01.798889Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{\n",
|
||||
" \"eta\": {\n",
|
||||
" \"sigma_um\": 1.482743287676068,\n",
|
||||
" \"sigma_err_um\": 0.023612628870164847,\n",
|
||||
" \"mtf50_lsf_lpmm\": 131.67127170307347,\n",
|
||||
" \"mtf200_lsf\": 0.18708166715602986,\n",
|
||||
" \"chi2_ndf\": 1.6091412712838244,\n",
|
||||
" \"mtf50_lpmm\": 126.38103081415967,\n",
|
||||
" \"mtf10_lpmm\": 230.34405458447614,\n",
|
||||
" \"rows_kept\": 1.0,\n",
|
||||
" \"photons\": 156697901.0\n",
|
||||
" },\n",
|
||||
" \"cluster 1ph\": {\n",
|
||||
" \"sigma_um\": 1.3517498054839803,\n",
|
||||
" \"sigma_err_um\": 0.02228742348935663,\n",
|
||||
" \"mtf50_lsf_lpmm\": 144.76471476919644,\n",
|
||||
" \"mtf200_lsf\": 0.22898527725431547,\n",
|
||||
" \"chi2_ndf\": 1.4377846589189212,\n",
|
||||
" \"mtf50_lpmm\": 138.62818723482948,\n",
|
||||
" \"mtf10_lpmm\": 252.66591450992405,\n",
|
||||
" \"rows_kept\": 1.0,\n",
|
||||
" \"photons\": 156697890.0\n",
|
||||
" },\n",
|
||||
" \"cluster <=2ph\": {\n",
|
||||
" \"sigma_um\": 1.3724427091990845,\n",
|
||||
" \"sigma_err_um\": 0.021926901151490465,\n",
|
||||
" \"mtf50_lsf_lpmm\": 142.69021685073372,\n",
|
||||
" \"mtf200_lsf\": 0.2230447974394754,\n",
|
||||
" \"chi2_ndf\": 1.5018077194468944,\n",
|
||||
" \"mtf50_lpmm\": 136.53803096715998,\n",
|
||||
" \"mtf10_lpmm\": 248.85636282080927,\n",
|
||||
" \"rows_kept\": 1.0,\n",
|
||||
" \"photons\": 205040034.0\n",
|
||||
" },\n",
|
||||
" \"cluster <=3ph\": {\n",
|
||||
" \"sigma_um\": 1.3855387111593214,\n",
|
||||
" \"sigma_err_um\": 0.017612306263149854,\n",
|
||||
" \"mtf50_lsf_lpmm\": 139.7355710728802,\n",
|
||||
" \"mtf200_lsf\": 0.2440890142229673,\n",
|
||||
" \"chi2_ndf\": 1.0195693691410581,\n",
|
||||
" \"mtf50_lpmm\": 135.24748433227265,\n",
|
||||
" \"mtf10_lpmm\": 246.50419222530726,\n",
|
||||
" \"rows_kept\": 1.0,\n",
|
||||
" \"photons\": 220757025.0\n",
|
||||
" },\n",
|
||||
" \"GridBased flat\": {\n",
|
||||
" \"sigma_um\": 1.3461043903325456,\n",
|
||||
" \"sigma_err_um\": 0.01889890619496615,\n",
|
||||
" \"mtf50_lsf_lpmm\": 143.7567164975865,\n",
|
||||
" \"mtf200_lsf\": 0.25887598776406284,\n",
|
||||
" \"chi2_ndf\": 1.1515016338976902,\n",
|
||||
" \"mtf50_lpmm\": 139.2095787481861,\n",
|
||||
" \"mtf10_lpmm\": 253.72556782676153,\n",
|
||||
" \"rows_kept\": 1.0,\n",
|
||||
" \"photons\": 230530601.0\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"written to /mnt/sls_det_storage/moench_data/MLXID/InferenceResults/GridBased/Edge_2filters_12keV/knife_edge_comparison.json\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"summary = {\n",
|
||||
" 'measurement': 'Edge/Flat_2filters_12keV',\n",
|
||||
" 'occupancy_percent': occupancy * 100, # flat field, ESF ROI\n",
|
||||
" 'roi_superpixel': list(ROI),\n",
|
||||
" 'bin_um': BIN_UM,\n",
|
||||
" 'bin_width_um': BIN_WIDTH_UM,\n",
|
||||
" 'convention': 'sigma = ODR p2 (Gaussian LSF); MTF50 = 1000 sqrt(ln 2 / 2) / (pi sigma); '\n",
|
||||
" 'ESF from DeepLearning/src, bin width 0.3 um',\n",
|
||||
" 'grid_model_epoch': grid_summary['epoch'],\n",
|
||||
" 'grid_frames': grid_summary['n_frames'],\n",
|
||||
" 'grid_subpixel_before': grid_summary['subpixel_nonuniformity_before'],\n",
|
||||
" 'grid_subpixel_after': grid_summary['subpixel_nonuniformity_after'],\n",
|
||||
" 'variants': {name: dict(sigma_um=float(r['sigma']), sigma_err_um=float(r['sigma_err']),\n",
|
||||
" mtf50_lsf_lpmm=float(r['mtf50_lsf']),\n",
|
||||
" mtf200_lsf=float(r['mtf200_lsf']),\n",
|
||||
" chi2_ndf=float(r['chi2_ndf']),\n",
|
||||
" mtf50_lpmm=float(r['mtf50']), mtf10_lpmm=float(r['mtf10']),\n",
|
||||
" rows_kept=float(r['rows_kept']), photons=float(r['photons']))\n",
|
||||
" for name, r in results.items()},\n",
|
||||
" 'relative_dqe_200lpmm': relative_dqe,\n",
|
||||
"}\n",
|
||||
"print(json.dumps(summary['variants'], indent=1))\n",
|
||||
"out = GRID / EDGE_RUN / 'knife_edge_comparison.json'\n",
|
||||
"json.dump(summary, open(out, 'w'), indent=1)\n",
|
||||
"print(f'\\nwritten to {out}')"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "pytorch_nightly",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.18"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,620 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d54c3f3e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Knife edge, 3 filters, pos0 — GridBased against the published chains\n",
|
||||
"\n",
|
||||
"Same measurement, same ROI, same ESF construction and same erf fit as\n",
|
||||
"`DeepLearning/Notebooks/KnifeEdge_3filters_pos0.ipynb`, so the only thing that\n",
|
||||
"differs between the rows of the final table is the reconstruction itself:\n",
|
||||
"\n",
|
||||
"| | |\n",
|
||||
"|---|---|\n",
|
||||
"| eta | classical eta interpolation from clusters |\n",
|
||||
"| cluster 1ph / ≤2ph / ≤3ph | cluster finder + the 1/2/3-photon CNNs, summed |\n",
|
||||
"| GridBased flattened | this repo, sub-pixel phase remapped (Rosenblatt) |\n",
|
||||
"\n",
|
||||
"The ESF code is the published one in `DeepLearning/src/funcs_postprocess.py`,\n",
|
||||
"the same that `Plotting/` uses.\n",
|
||||
"\n",
|
||||
"**Edge width (revised 2026-09-28).** The ESF is binned and fitted exactly as\n",
|
||||
"`Plotting/fig_knife_edge.py --fit odr` does it: `generate_presampled_esf()` and\n",
|
||||
"`get_odr_fitting()` from `DeepLearning/src/funcs_postprocess.py` (bin content\n",
|
||||
"Σk/Σf), symmetric ±4σ window, **ESF bin width 0.3 µm**. The ODR model is\n",
|
||||
"`p0/2 (1 + erf((x - p1)/(sqrt(2) sigma))) + p3`, so the fit gives **sigma**, the\n",
|
||||
"width of the Gaussian LSF, which is what the tables quote, with\n",
|
||||
"`MTF50 [lp/mm] = 1000 sqrt(ln 2 / 2) / (pi sigma)`; MTF50 and MTF(200 lp/mm) are\n",
|
||||
"also measured from the LSF (`Plotting/knife_edge_numbers.py`: first crossing,\n",
|
||||
"central-difference correction), and the relative DQE uses the latter. Only the\n",
|
||||
"flattened GridBased reconstruction is analysed. Same processing as\n",
|
||||
"`KnifeEdge_poly2to20keV_Moench040.ipynb`.\n",
|
||||
"\n",
|
||||
"**Occupancy** is that of the flat field inside the ESF ROI: the reconstructed\n",
|
||||
"photons per 25 µm pixel per frame over `ROI // 10` (x 33–46, y 26–49 of the\n",
|
||||
"99 × 99 frame), the pixels over which `DeepLearning/Notebooks/KnifeEdge_3filters_pos0.ipynb`\n",
|
||||
"sums the deposited energy (0.705 % at 3 filters from the energy, 0.747 % here\n",
|
||||
"from the photons of the 12 keV model).\n",
|
||||
"\n",
|
||||
"*Until 2026-09-28 this notebook took the fitted sigma for sqrt(2) sigma (so its\n",
|
||||
"MTF50 was sqrt(2) too high), used 0.5 µm bins, and binned the ESF with an older\n",
|
||||
"copy of `generate_presampled_esf` (inverse-variance mean of k/f, biased low in\n",
|
||||
"the toe, sigma ~3 % too small). The previous version is in\n",
|
||||
"`Backup_260928_pre_sigma_fix/`.* The published MTF50\n",
|
||||
"of 149 lp/mm corresponds to sigma = 1.26 µm.\n",
|
||||
"\n",
|
||||
"Run in the `pytorch_nightly` environment (ROOT + scipy + jupyter)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "bbf5c366",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:50.007938Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:50.007862Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:51.585942Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:51.585615Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Welcome to JupyROOT 6.28/10\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import json\n",
|
||||
"import sys\n",
|
||||
"from pathlib import Path\n",
|
||||
"\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"REPO = Path('/home/xie_x1/MLXID/GridBased')\n",
|
||||
"sys.path.insert(0, '/home/xie_x1/MLXID/DeepLearning/src') # the code Plotting/ uses\n",
|
||||
"sys.path.insert(0, '/home/xie_x1/MLXID/Plotting')\n",
|
||||
"from ROOT import TCanvas, gROOT\n",
|
||||
"gROOT.SetBatch(True)\n",
|
||||
"from funcs_postprocess import generate_presampled_esf, get_odr_fitting\n",
|
||||
"from knife_edge_numbers import mtf as mtf_from_lsf # first crossing, sinc-corrected\n",
|
||||
"\n",
|
||||
"GRID = Path('/mnt/sls_det_storage/moench_data/MLXID/InferenceResults/GridBased')\n",
|
||||
"PUBLISHED = Path('/home/xie_x1/MLXID/DeepLearning/InferenceResults')\n",
|
||||
"ETA = Path('/home/xie_x1/MLXID/EtaInterpolation/Results')\n",
|
||||
"\n",
|
||||
"EDGE_RUN, FLAT_RUN = 'Edge_3filters_pos0_12keV', 'Flat_3filters_pos0_12keV'\n",
|
||||
"BIN_UM = 2.5 # super-pixel = 25 um / 10\n",
|
||||
"ROI = (330, 465, 260, 490) # x1, x2, y1, y2, as published\n",
|
||||
"CROP = slice(10, -10) # 1010 -> 990, as published\n",
|
||||
"BIN_WIDTH_UM = 0.3 # presampled ESF bin, as Plotting/ and the manuscript\n",
|
||||
"\n",
|
||||
"plt.rcParams.update({'figure.dpi': 110, 'image.cmap': 'gray',\n",
|
||||
" 'image.origin': 'lower', 'image.interpolation': 'nearest'})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c749780c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1. Load every reconstruction of the same measurement"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "3b145751",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:51.587508Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:51.587285Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:51.804809Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:51.804521Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"GridBased model epoch 135, 14,000,000 frames, occupancy 0.747 % (flat field, ESF ROI)\n",
|
||||
" sub-pixel excess rms 22.63 % -> 4.30 % after flattening\n",
|
||||
"\n",
|
||||
"variant edge photons flat photons relative to <=3ph\n",
|
||||
"eta 1.6099e+08 2.7823e+08 0.855\n",
|
||||
"cluster 1ph 1.6099e+08 2.7823e+08 0.855\n",
|
||||
"cluster <=2ph 1.8464e+08 3.1950e+08 0.981\n",
|
||||
"cluster <=3ph 1.8828e+08 3.2591e+08 1.000\n",
|
||||
"GridBased flat 1.9083e+08 3.3060e+08 1.014\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def crop(image):\n",
|
||||
" \"\"\"The published frames are cropped by 10 super-pixels on each side.\"\"\"\n",
|
||||
" return image[CROP, CROP] if image.shape[0] == 1010 else image\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def published(run, experiment, n_photons):\n",
|
||||
" name = f'{n_photons}Photon_ML_superFrame_etaInterpolated.npy'\n",
|
||||
" return np.load(PUBLISHED / run / experiment / 'augX1' / name).astype(float)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"EXPERIMENT = {1: '1ph_260512_12keV_v260511_06',\n",
|
||||
" 2: '2ph_260610_12keV_v260610_01',\n",
|
||||
" 3: '3ph_260611_12keV_v260611_00'}\n",
|
||||
"KNIFE, FLAT = 'KnifeEdge_3filters_pos0', 'FlatField_3filters_pos0'\n",
|
||||
"\n",
|
||||
"cluster_edge = {n: published(KNIFE, EXPERIMENT[n], n) for n in (1, 2, 3)}\n",
|
||||
"cluster_flat = {n: published(FLAT, EXPERIMENT[n], n) for n in (1, 2, 3)}\n",
|
||||
"\n",
|
||||
"grid_summary = json.load(open(GRID / EDGE_RUN / 'summary.json'))\n",
|
||||
"flat_summary = json.load(open(GRID / FLAT_RUN / 'summary.json'))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def grid_image(run, flattened):\n",
|
||||
" name = 'binned_image_flattened.npy' if flattened else 'binned_image.npy'\n",
|
||||
" return np.load(GRID / run / name).astype(float)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"variants = {\n",
|
||||
" 'eta': (np.load(ETA / '2603MaxIV_Edge3Filters_pos0_12keV_fromClusters.npy'),\n",
|
||||
" np.load(ETA / '2603MaxIV_FlatField3Filters_pos0_12keV_fromClusters.npy')),\n",
|
||||
" 'cluster 1ph': (cluster_edge[1], cluster_flat[1]),\n",
|
||||
" 'cluster <=2ph': (cluster_edge[1] + cluster_edge[2], cluster_flat[1] + cluster_flat[2]),\n",
|
||||
" 'cluster <=3ph': (cluster_edge[1] + cluster_edge[2] + cluster_edge[3],\n",
|
||||
" cluster_flat[1] + cluster_flat[2] + cluster_flat[3]),\n",
|
||||
" 'GridBased flat': (grid_image(EDGE_RUN, True),\n",
|
||||
" grid_image(FLAT_RUN, True)),\n",
|
||||
"}\n",
|
||||
"variants = {name: (crop(edge), crop(flat)) for name, (edge, flat) in variants.items()}\n",
|
||||
"\n",
|
||||
"def flat_occupancy(run):\n",
|
||||
" # reconstructed photons per 25 um pixel per frame in the flat field, inside the\n",
|
||||
" # ESF ROI: ROI // 10 in pixels of the 99 x 99 frame, both ends included as in\n",
|
||||
" # DeepLearning/Notebooks; +1 because the 101 x 101 frame is cropped by 1 px\n",
|
||||
" summary = json.load(open(GRID / run / 'summary.json'))\n",
|
||||
" native = np.load(GRID / run / 'native_image.npy') / summary['n_frames']\n",
|
||||
" x0, x1, y0, y1 = (v // 10 for v in ROI)\n",
|
||||
" return float(native[y0 + 1:y1 + 2, x0 + 1:x1 + 2].mean())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"occupancy = flat_occupancy(FLAT_RUN)\n",
|
||||
"print(f\"GridBased model epoch {grid_summary['epoch']}, \"\n",
|
||||
" f\"{grid_summary['n_frames']:,} frames, \"\n",
|
||||
" f\"occupancy {occupancy*100:.3f} % (flat field, ESF ROI)\")\n",
|
||||
"print(f\" sub-pixel excess rms {grid_summary['subpixel_nonuniformity_before']*100:.2f} % -> \"\n",
|
||||
" f\"{grid_summary['subpixel_nonuniformity_after']*100:.2f} % after flattening\\n\")\n",
|
||||
"print(f\"{'variant':16s} {'edge photons':>14} {'flat photons':>14} relative to <=3ph\")\n",
|
||||
"reference = variants['cluster <=3ph'][0].sum()\n",
|
||||
"for name, (edge, flat) in variants.items():\n",
|
||||
" print(f'{name:16s} {edge.sum():14.4e} {flat.sum():14.4e} {edge.sum()/reference:8.3f}')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "7e4f857c",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:51.805974Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:51.805891Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:52.219065Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:52.218827Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAABmcAAAH2CAYAAACFuVjoAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AAEAAElEQVR4nOydeZgU1bn/v92z9d49MwzIoqAQg0RQ8YqKC4ioAVTcIhCN4oa7xu3GGBX0F2OMa6LXFcVdXKJEA24IeqMxek2MUSHuCxJFlll6umef+v3B8z3z1pnqnp4dZt7P88zDTHd11alTRb/ferfjcxzHgaIoiqIoiqIoiqIoiqIoiqIoitIj+Ht7AIqiKIqiKIqiKIqiKIqiKIqiKP0JDc4oiqIoiqIoiqIoiqIoiqIoiqL0IBqcURRFURRFURRFURRFURRFURRF6UE0OKMoiqIoiqIoiqIoiqIoiqIoitKDaHBGURRFURRFURRFURRFURRFURSlB9HgjKIoiqIoiqIoiqIoiqIoiqIoSg+iwRlFURRFURRFURRFURRFURRFUZQeRIMziqIoiqIoiqIoiqIoiqIoiqIoPYgGZxRFURRFURRFURRFURRFURRFUXoQDc4oiqIoiqIoiqIoiqIoiqIoiqL0IBqcURRFURRF6cfcf//98Pl8ePXVV7t0v6+++ip8Ph/uv/9+1+vpdBrnnXcetttuO+Tl5WHEiBFdetyuYPLkyVvkuDpLpmuSDZ/Ph7lz53bbmLrr/ust5s6dC5/Pl/P2I0aMwOTJk12vdfT+68j17Qr66v8XRVEURVEUReluNDijKIqiKIqi9BjXXXcdbr31VsyaNQv3338/brnllt4eUr+moqICCxYs6NbgyKuvvooFCxagoqKi246hbB2MGDECPp8v48+CBQtc23/55Zc488wzsdNOOyEcDiORSGDHHXfE7Nmz8fTTT7u2nTx5csb9jho1qs2xLViwwPUZv9+PRCKB/fbbDw899FDWz7744os48sgjMXjwYBQWFqKsrAyHHHIIFi9eDMdxMh7r9ddfb3vSFEVRFEVRlD5Lfm8PQFEURVEURel77L///qipqUFBQYHr9Zdffhljx47F9ddf30sj6794XZOKigpcddVVANCqgqOrePXVV3HVVVdh7ty5SCQS3XKMvsRLL73k6dDvKwwaNAg33HCD53vjxo0zv//jH//A/vvvj6amJhx33HE455xzAACffvopli5diurqahx11FGuz/v9fjzwwAOt9huNRnMe3xVXXIEdd9wRTU1N+Prrr7Fw4UKccMIJWLt2LS699FLXts3NzTjjjDNwzz33YOTIkZg3bx6GDx+OdevW4cknn8ScOXPw6KOP4vHHH0cwGMx5DIqiKIqiKEr/QIMziqIoiqIoSpfj9/sRCARavf7dd99hu+2264URKZmuibJlUVhY2NtD6FYikQiOP/74NrdbsGABUqkUlixZgpkzZ7reu/nmm/HNN9+0+ozP58tp39k4+OCDse+++5q/Tz75ZOy444647rrrcMkllyAvL8+89+tf/xr33HMPjj76aDzyyCMoKioy71166aW4+OKLcdNNN+Gcc87Bvffe26lxKYqiKIqiKH0PbWumKIqiKIqitOKOO+5Afn4+jj32WNTV1QFoWR/j448/xsyZMxGPxxGJRDBjxgx89tlnrs/b61+wjc8XX3yB1157zbON0bvvvotjjjkGAwcORGFhIXbYYQdceumlSKfTOY/7s88+w9y5czFkyBAUFhZi2LBhOOuss7Bhw4ZW23766ac48sgjEY/HEY1GcfDBB+O9997LuO+HHnoI48aNQ1FREYYNG4b//u//xurVqz3bMTmOg3vuuQcTJkxAOBxGOBzGxIkTsWTJkpzPxWbt2rXw+Xy46KKLXK/PmzcPPp8Pp59+uuv1Cy+8ED6fD+vWrQPQ+prcf//92H777QEAV111lbkmXuuHvP3225gyZQoikQgSiQTmzJmD9evXtznmyZMnm8qc7bffPmP7KsdxcMstt2DHHXdEUVERdthhB9x8882e++zsfcI1Ur766iscffTRKC4uRjgcxkEHHYR//vOfrm2zrePCe/rLL79s9d7GjRtx8skno6ysDMFgEBMnTsSKFSvaNT7J6tWrMWfOHGy77bYoKirCwIEDsc8++2DRokWe++C9GggEMHToUPzqV79CU1NTq+268/9LZ/n4448BAAceeKDn+8OGDeu2Y0uGDh2KnXbaCRUVFa57fsOGDfjtb3+LoUOH4oEHHnAFZoDNgaLrr78eu+++OxYtWoQPP/ywR8arKIqiKIqibD1o5YyiKIqiKIpicBwHv/zlL3HdddfhggsuwI033uha4Hzt2rXYf//9cfjhh+O6667DJ598gltvvRWHH3443n//ffj93rk/Rx11FEaNGoULLrgAAwYMwK9+9SsALW2MXnjhBRxxxBHYdtttce6552LQoEF47733cNNNN+GNN97AypUrkZ+fXbr+85//xOTJkxEKhXDyySdj+PDh+OSTT3DHHXfglVdewdtvv414PA4AWLNmDSZOnIiKigqcccYZ2GmnnfDmm29i8uTJKC0tbbXv//mf/8E555yD0aNH46qrrkJBQQEee+yxjGu1nHTSSXjwwQcxc+ZMHHfccQCAp59+GkceeSTuuOMOnHHGGdkvhAdDhw7F6NGjsXz5ctfrr7zyCvx+v+frO++8MwYNGuS5v/333x8333wzLrjgAhx55JGmRVQkEnFt995772HatGk44YQTMGvWLPz973/HwoULUV5ejhdeeCHrmH/1q1+hpKQEzzzzDG6++WYMGDAAgLt9FQBcdtllqKqqwkknnYRIJIIHH3wQF154IQYPHozZs2eb7briPgGAVCqFSZMmYbfddsOvf/1rrFmzBv/zP/+D/fbbD2+++SZ23nnnNveRjUMOOQSxWAxXXHEFNm3ahDvvvBOHHHIInn/+eUydOrVd+9q4cSMOOOAANDc34/TTT8f222+P8vJyvP/++3jttddw0kknuba/6667sHbtWpx66qkoKyvD008/jd/85jeIRqOutlzd+f8lG83NzZ7BHwBIJBLm+o0cORIfffQRFi5ciPPPP9/1PZQNr33H4/FWLRZzpb6+HmvWrDFr0JClS5eipqYGP/vZzxAOhz0/6/f7MW/ePJx++un44x//iB/96EcdGoOiKIqiKIrSR3EURVEURVGUfsuiRYscAM7KlSud2tpaZ/bs2Y7f73d+//vft9p2+PDhDgDn0Ucfdb1+7bXXOgCcF1980by2cuVKB4CzaNGiVvuYNGmS67Wamhpnm222cSZMmODU1ta63nvyyScdAM7999/f5rnsuuuuzvbbb+9s3LjR9frf/vY3x+/3OwsWLDCv/exnP3MAOM8884znuQwfPty8Vl5e7oTDYWeHHXZwqqqqzOu1tbXOHnvs4QBw5s+fb15fsmSJA8C56aabWo3x0EMPdWKxmGs/7eHss892fD6fs27dOsdxHOeLL75wAJjz+fzzzx3HcZzvv//e8fl8zvnnn28+63VN+Hk5fgkAx+fzOa+//rrr9dNPP90B4Hz00Udtjnn+/PkOAOeLL75o9R7vv3HjxrmufXV1tVNaWursvffe5rWuuk8mTZrkAHDOPvts1+tvvfWW4/P5nAMPPNC8luk+znReJ554ogPAOeyww5ympibz+pdffumEQiHnBz/4gdPc3Gxe9/r/MGnSJNf996c//ckB4CxevDjreXGs22yzjbNp0ybzelNTk7PTTjs5gwcPdm3fXf9fssHvkEw/f/nLX1zjKCwsdAA42223nXPCCSc4t956q/PPf/7Tc9+8rl4/zz//fJtj4/X885//7Kxfv95Zt26d8/bbbztHHnmkA8CZPXu2a/uLLrrIAeD88Y9/zLrfd955xwHgHH300a2OJc9XURRFURRF6X9oWzNFURRFURQF5eXlOPjgg7FkyRI8+eSTOO+88zy3GzJkCObMmeN67aCDDgLQ0oaovSxfvhzfffcd5s6di2QyiQ0bNpifSZMmIRwO48UXX8y6jw8++AD//Oc/MXv2bJOZz5+RI0fiBz/4gdlHc3MzlixZgjFjxuCII45w7efnP/95q8qRl156CalUCmeddZZrYfGioiJccMEFrcby0EMPIRgMYtasWa5xbNiwAUceeSSqqqrw5ptvdmiuDjzwQDiOY1pkvfLKK8jLy8NVV12FvLw8vPLKKwCAFStWwHGcjC2h2sPee++NffbZx/VaZ6+5zTnnnONqCxUOh7H33nu79t8V94nksssuc/09YcIETJ06FStWrEB5eXmnzueXv/ylq4ps+PDhOO644/DJJ5/gX//6V7v2xWqNZcuWobKyss3tTz75ZBQXF5u//X4/DjzwQHz77beorq4G0L3/X9piyJAhePnllz1/xo4da7bbc8898Y9//AOnnHIKGhsb8eCDD+Lcc8/FrrvuivHjx7dqQcdz9drvHnvskfP4Dj30UJSVlWHQoEGYMGECnn32WZx55pmt1ozhtWB1USb4fi7XTlEURVEURelfaFszRVEURVEUBXPnzkVVVRVefvnlrG2Xdthhh1avsa3Rxo0bO3Ts1atXAwDOOussnHXWWZ7bcN2UtvZx7bXX4tprr/XchmP//vvvkUwmMWbMmFbbBAIBjBw5EhUVFea1zz//HAAwevToVtvvtNNOnmOpqanB0KFDM463rfPJxAEHHGBamM2ePRvLly/H7rvvju233x7jx4/H8uXLceqpp2L58uXIy8vDpEmTOnQcSXdc81yPIfffFfcJSSQSGDJkSKvXx4wZg5dffhmff/45dt9995z25YXXvcXXPv30U+yyyy4572v//ffHySefjPvuuw+PPfYYdt99d0ycOBHHHHMM9t5771bbt3W9IpFIt/5/aYtgMJhza7cf/ehHWLhwIQDgm2++wRtvvIEHH3wQy5Ytw/Tp0/Hhhx+Line truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1650x506 with 6 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"fig, axes = plt.subplots(1, 3, figsize=(15, 4.6))\n",
|
||||
"extent = [0, 990 * BIN_UM, 0, 990 * BIN_UM]\n",
|
||||
"for ax, name in zip(axes, ('eta', 'cluster <=3ph', 'GridBased flat')):\n",
|
||||
" image = variants[name][0]\n",
|
||||
" im = ax.imshow(image, extent=extent, vmax=np.percentile(image, 99.5))\n",
|
||||
" ax.add_patch(plt.Rectangle((ROI[0]*BIN_UM, ROI[2]*BIN_UM),\n",
|
||||
" (ROI[1]-ROI[0])*BIN_UM, (ROI[3]-ROI[2])*BIN_UM,\n",
|
||||
" edgecolor='red', facecolor='none', lw=1.4))\n",
|
||||
" ax.set_title(name); ax.set_xlabel('x [um]'); ax.set_ylabel('y [um]')\n",
|
||||
" plt.colorbar(im, ax=ax, fraction=0.046)\n",
|
||||
"fig.suptitle('knife edge, with the published ESF ROI')\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8b8c560d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2. Edge spread function\n",
|
||||
"\n",
|
||||
"`generate_presampled_esf` fits an erf to every row of the ROI, fits a straight\n",
|
||||
"line through the edge positions, and re-samples the ROI onto a common axis;\n",
|
||||
"`get_odr_fitting` then fits the erf with x and y errors inside |x - p1| <= 4 sigma\n",
|
||||
"(the fit of `Plotting/fig_knife_edge.py --fit odr`)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "ae7f236f",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:52.220504Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:52.220382Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:53.851025Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:53.850763Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Final Edge Midpoint Fit: slope = -0.0866, intercept = 433.2062, chi2/ndf = 0.0458\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0859, intercept = 432.9570, chi2/ndf = 0.0451\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0858, intercept = 433.0080, chi2/ndf = 0.0419\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0859, intercept = 433.0672, chi2/ndf = 0.0473\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0860, intercept = 433.1036, chi2/ndf = 0.0451\n",
|
||||
"variant sigma [um] chi2/ndf MTF50 MTF50 LSF MTF(200) LSF rows\n",
|
||||
"eta 1.536 +- 0.019 1.06 122.0 127.4 0.170 100%\n",
|
||||
"cluster 1ph 1.355 +- 0.016 0.69 138.3 140.7 0.225 100%\n",
|
||||
"cluster <=2ph 1.380 +- 0.016 0.81 135.8 138.1 0.221 100%\n",
|
||||
"cluster <=3ph 1.381 +- 0.017 0.85 135.7 136.8 0.229 100%\n",
|
||||
"GridBased flat 1.360 +- 0.019 1.10 137.8 140.3 0.252 100%\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def analyse(edge_image, flat_image, label):\n",
|
||||
" esf = generate_presampled_esf(edge_image, flat_image, ROI,\n",
|
||||
" pixel_size_um=BIN_UM, bin_width_um=BIN_WIDTH_UM,\n",
|
||||
" chi2_threshold=15.0, residual_tolerance_px=1.0)\n",
|
||||
" x, z = esf['numpy']['x'], esf['numpy']['z']\n",
|
||||
" odr = get_odr_fitting(x, z, esf['numpy']['x_err'], esf['numpy']['z_err'], n_sigma=4.0)\n",
|
||||
" sigma, sigma_err = odr['sigma_um'], odr['sigma_err_um'] # sigma of the Gaussian LSF\n",
|
||||
" try:\n",
|
||||
" mtf50_lsf, mtf200_lsf = mtf_from_lsf(dict(x=x, z=z, pars=odr['beta']))\n",
|
||||
" except Exception:\n",
|
||||
" mtf50_lsf = mtf200_lsf = np.nan\n",
|
||||
" n_fit = int(odr['mask'].sum())\n",
|
||||
" ndf = max(n_fit - len(odr['beta']), 1)\n",
|
||||
" x_fit = x[odr['mask']]\n",
|
||||
" return dict(label=label, x=x, z=z, sigma=sigma, sigma_err=sigma_err, sigma_gauss=sigma,\n",
|
||||
" chi2_ndf=odr['chi2_ndf'], chi2=odr['chi2_ndf'] * ndf, ndf=ndf,\n",
|
||||
" mtf50=1000 * np.sqrt(np.log(2) / 2) / (np.pi * sigma),\n",
|
||||
" mtf10=1000 * np.sqrt(np.log(10) / 2) / (np.pi * sigma),\n",
|
||||
" mtf50_lsf=mtf50_lsf, mtf200_lsf=mtf200_lsf,\n",
|
||||
" rows_kept=esf['valid_lines_ratio'],\n",
|
||||
" edge_slope=esf['edge_slope'], edge_centre=odr['beta'][1],\n",
|
||||
" fit_points=n_fit, fit_range=(x_fit.min(), x_fit.max()),\n",
|
||||
" photons=float(edge_image.sum()), odr=odr)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"results = {name: analyse(edge, flat, name) for name, (edge, flat) in variants.items()}\n",
|
||||
"\n",
|
||||
"print(f\"{'variant':16s} {'sigma [um]':>16} {'chi2/ndf':>9} {'MTF50':>7} {'MTF50 LSF':>9} \"\n",
|
||||
" f\"{'MTF(200) LSF':>12} {'rows':>6}\")\n",
|
||||
"for name, r in results.items():\n",
|
||||
" print(f\"{name:16s} {r['sigma']:7.3f} +- {r['sigma_err']:.3f} {r['chi2_ndf']:9.2f} {r['mtf50']:7.1f} \"\n",
|
||||
" f\"{r['mtf50_lsf']:9.1f} {r['mtf200_lsf']:12.3f} {r['rows_kept']*100:5.0f}%\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "bc41a64f",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:53.852183Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:53.852031Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:54.250652Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:54.250431Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAABVMAAAIECAYAAAAU8b4kAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AAEAAElEQVR4nOzdd1hUx9fA8e/SBJaqNOn2XmPXBOzGrjG2aMTeS8hPE1vs3dgLMUXUWKLG3k3siUaNBRW7ICg2lCaIwO59/+Bl48qiYBDQnM/z7CN779w75467MHt27oxKURQFIYQQQgghhBBCCCGEEK9klNsBCCGEEEIIIYQQQgghxLtAkqlCCCGEEEIIIYQQQgiRCZJMFUIIIYQQQgghhBBCiEyQZKoQQgghhBBCCCGEEEJkgiRThRBCCCGEEEIIIYQQIhMkmSqEEEIIIYQQQgghhBCZIMlUIYQQQgghhBBCCCGEyARJpgohhBBCCCGEEEIIIUQmSDJVCCGEEEIIIYQQQgghMkGSqUIIIYQQQgghhBBCCJEJkkwVQoj/iNDQUFQqFePHj3+nzi2EEEIIkVdotVrGjx9P4cKFMTExQaVS5XZI2SYwMBCVSsWhQ4dytN6DBw9So0YNrK2tUalUBAYGcujQId3PeYmvry/e3t65HYYQIpdJMlUIIUSOSuscv+oRGhqqd8zOnTtp3Lgxnp6e5MuXDxcXF6pWrcrQoUO5deuWrlxaUjejx+TJk3P4aoUQQgjxKi/2C7p162awjKIoeHt7o1KpMDExSXdcZh6ZOebnn39+bbwrVqxgwoQJ1K1blx9//JFVq1ZlX2PkgEOHDjF+/Hiio6NzOxQAoqKiaNu2LfHx8Xz77besWrWKjz76yGDZ6Ohoxo8fn2Gyd968eXkq+Zr2ms3o8fIghNDQUPr370+pUqVQq9XY2dlRvHhxOnbsyKZNm/TK+vr6ZnjeokWL5uBVCvHfZJLbAQghhPhvateuHa1atTK4z9HRUffzyJEjmT59OoULF6Z79+54eHjw6NEjLl68yPLly/nwww8pXLiw3vG+vr707Nkz3XkrVqyYrdcghBBCiOxhbm7Oxo0bWbhwITY2Nnr79u/fz+3btzE3Nyc5ORmAUqVKpUtkbtq0ic2bN9OnTx8+/PDDDOvKqA9Su3bt18a5f/9+bG1t+eGHH97JUamHDh1iwoQJ+Pn5YWdnl9vhcOrUKaKjo/nxxx9p27atbru3tzfPnj3D1NRUty06OpoJEyYAqX29l82bNw9vb2/8/PzedtiZ5uzszOzZsw3uK1++vO7nM2fO8NFHH6HRaPjss88YNGgQADdu3GDnzp08ffpUr30AjIyMWLFiRbrzWltbZ+MVCCEMkWSqEEJkID4+HrVandthvLcqVKhAly5dXlnm0aNHzJo1C09PT86ePZvuw9WzZ8949uxZuuOKFCny2nMLIYQQIu9o27Yta9asYe3atfTt21dv3w8//ICnpydeXl78+eefQGqS6uW/9Tdu3GDz5s3UrFnzlf2AzPRBMnL//n3s7OwylUh9/vw5xsbGutG0Ir379+8DkD9/fr3tRkZGmJub50ZI2crKyipTr7Xx48cTHx/Pli1b0iX6586dy507d9Ido1KppL8rRC6R2/yFELkuOjoaf39/ChUqRL58+XB2dqZTp05cv35dVyY2Nha1Wk3Dhg0NniNtjqcXv51VFIXvv/+eatWqoVarUavV1KpViy1btqQ7XqVS4efnx6FDh/D19cXGxoayZcsCqR3hSZMmUbp0adRqNTY2NpQsWZKePXvy/Plz3Tn27dtHp06dKFKkCBYWFtjY2ODj48POnTvT1efn54dKpeLJkyf06tULJycnrKysaNSoke66t23bRtWqVbG0tMTNzY3p06enO4+3tze+vr6cP3+eRo0aYW1tja2tLZ988gkhISGZ+w8Afv31V3x8fLCxscHCwoJKlSrxww8/GCy7du1aKlSogLm5OW5ubvj7+5OQkJDpurLi5s2baDQaqlatmi6RCmBhYZGu8y2EEEKId0+pUqWoVasWP/74o972yMhItm7dSvfu3TEyyr2Pr2l9zYMHD3L79m3dLdVpoyDT5tK8ffs2HTt2xMHBAXNzc10S7O7du/Tq1Qs3NzfMzMxwd3enT58+3Lt3T6+eF+cKXbZsGaVLl8bc3JzixYuzcuVK3bk6duxIgQIFUKvVtG7dWpeUfBVfX1/dyM5ChQpleLu5oijMmzeP4sWLky9fPgoXLszcuXMNnvPs2bO0a9cOJycnzMzMKFy4MF9//XWm+oYvTu1Qt25dg1MypN22HxgYSKFChQCYMGGCrqy3t7dumqfbt29z+PDhDKeOunnzJn5+fri6uur+DwYMGEBkZGS62G7cuEGbNm2wtbXF2tqaRo0acf78+dde05u6du0aAPXr1ze4393d/a3VLYTIOvmKTAiRq+Li4qhduzbBwcF89tln1KpVi5s3b7JkyRL27NnDH3/8QenSpbGxsaFNmzasXbuWO3fupOtQBAYGYmVlRbt27XTbunfvzsqVK2nVqhWfffYZkHr7V5s2bVi6dCn9+vXTO8fp06f59ddf6d69O507dyYuLg6AQYMG8cMPP/DZZ58xZMgQAEJCQti+fTvPnj0jX758uhgePHhAly5dcHd359GjR6xYsYLmzZuzYcMGvdjSNGnSBGdnZ8aNG0dERARz5syhUaNGTJo0iS+//JJ+/frRvXt31q1bx8iRI/Hy8qJTp05657hz5w5169alZcuWzJw5k+DgYL777juOHz/O33//TcGCBV/5fzB+/Hjd3F/jxo3DwsKCvXv30rt3b27cuKGXxA0ICKB///4UL16ccePGYWpqyurVqzly5Mgr6zAkISHBYOfV2NgYe3t7AAoXLoxKpeLIkSNcvXqVEiVKZOrcz58/T3duIyMjSbwKIYQQeVivXr3o0aMHFy5coFy5cgCsXLmSlJQUunfvnm0LIxnqg5iammJra5vhMR999BGrVq1iypQpREZG6pKLRYoU0ZV5+vQpH374IdWqVWPChAnExcVhZWXF3bt3qVq1Kg8fPqR3796UL1+e8+fP8/3337Nnzx5OnTqFs7OzXn1Llizh0aNH9O7dGysrK3744Qe6deuGqakpI0eO5MMPP2Ty5MlcuXKFxYsX061bN/bu3fvK6x49ejT58+dn8+bNzJ07FwcHB0D/dnOAUaNGERsbS/fu3bGysmLlypX4+/tTsGBBOnbsqCu3Z88eWrdujYeHB4MHD8bZ2Znz588zZ84c/vjjDw4ePPjKUbmrVq3i6NGjLFu2jFGjRlGqVKlXtv/cuXP54osvaNOmje6WdysrKxwdHVm1ahVffPEFDg4OjB49Wndc2tRR586dw9fXF0tLS3r06IGXlxfXr19n6dKl/P7775w8eVL3/x8eHk6tWrWIjo6mX79+lCpViuPHj+Pr60uBAgVe2cYv02q1Bvu7AHZ2drr2KVKkCFevXuWHH35g6NChmZ5CwtC5bW1t9aZHEEK8BYoQQuSisWPHKoAyY8YMve2HDh1SAKV+/fq6bb/99psCKFOmTNEre+vWLUWlUindu3fXbduyZYsCKHPmzElXZ/PmzRUbGxslNjZWtw1QAGXfvn3pytvb2ytNmjR57bU8ffo03bb4+HilePHiSpkyZfS2d+vWTQGUvn376m2fO3euAihWVlZKSEiIbntiYqLi7Oys1KxZU6+8l5eXAiizZs3S275+/XoFUHr27KnbFhISogDKuHHjdNvOnj2rqFQqZciQIeliHzhwoGJkZKTcvHlTURRFiY6OVqysrBRPT08lOjpaVy4hIUGpWLFiunNn5ODBg7r2NvQoUqSIXvmhQ4cqgGJsbKxUr15d8ff3V3755Rfl4cOH6c6ddo2GHs7Ozq+NTQghhBA5K61fMGnSJOXp06eKtbW1MnToUN3+0qVLK40aNVIURVF8fHwUY2PjDM81btw4BVCWL1/+yroMPapXr56peH18fBQvLy+D2wFl1KhR6fZ17dpVAZRffvlFb/uKFSvS9dfSYnRxcVGePHmi237//n0lX758ikqlStdvTusrXb169bXxp7XRi/3MNMuXL1cApXz58kpiYqJu+9OnT5UCBQro9UOfPXumuLi4KNWqVdMrqyiKsmHDBgVQAgMDXxtPWp0HDx7U257WDi/+Xxrqy77Iy8tL8fHxMbivYsWKSqFChZTHjx/rbT9x4oRiZGSkjB8/Xrct7f9r8+bNemWnTZumAAb//zOK51V93qNHj+rFYWZmpgCKp6en8vnnnysLFy5Uzp07Z/Dcaa83Q4/du3dnKj4hxJuT2/yFELnq119/xdbWlqFDh+pt9/HxoW7duhw4cICoqCgA6tWrh6enZ7qJ1lesWIGiKHqTza9atQoLCws6dOhAZGSk3qNNmzbExsZy/PhxvfNUqFDB4DQCdnZ2XLp0iaCgoFdey4vzq8bHx/P48WMSEhKoV68ely5d0o10fdGXX36Z7roBWrZsibe3t257vnz5qF69uu4WoBdZW1szePBgvW2ffvopxYsXZ9OmTSiKkmHMP//8M4qi0LNnz3Tt1KpVK7RaLb/99huQOo3B06dPGTRokN7IDQsLC/73v/+9omUM8/PzY//+/ekeabewpZk7dy6rV6/G19eXoKAg5syZQ4cOHXB1daVv374G50z9+OOP0513w4YNWY5RCCGEEDlHrVbTsWNHfv75Z5KSkvjzzz8JDg6mV69e2VqPoT7IwoULs+Xcw4cP13uu1WrZsmULJUuWpH379nr7unbtSpEiRQz213r06KG7UwdS54gtUaIEKpVKd6dUmrT+o6F+4psYNGiQ7s4rSP1/qVmzpt75f/vtN+7fv4+fnx9xcXF6fUgfHx/UavVrR8rmlIsXL3Lu3Dk6duyoGyma9ihSpAjFihXTxZr2/1W6dGlat26td55hw4ZhZWWVpbpdXV0N9nf379+vG30NUL1Line truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1375x528 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"fig, ax = plt.subplots(1, 2, figsize=(12.5, 4.8))\n",
|
||||
"colours = {'eta': '#a0451c', 'cluster 1ph': '#6b6b6b', 'cluster <=2ph': '#7b5aa6',\n",
|
||||
" 'cluster <=3ph': '#4b2a6b', 'GridBased raw': '#4cbcac', 'GridBased flat': '#10695f'}\n",
|
||||
"frequency = np.linspace(0, 400, 2000)\n",
|
||||
"for name, r in results.items():\n",
|
||||
" ax[0].plot(r['x'], r['z'], lw=1.1, color=colours[name],\n",
|
||||
" label=f\"{name}: $\\\\sigma$ = {r['sigma']:.3f} $\\\\pm$ {r['sigma_err']:.3f} $\\\\mu$m\")\n",
|
||||
" sigma_mm = r['sigma_gauss'] / 1000.0\n",
|
||||
" ax[1].plot(frequency, np.exp(-2 * np.pi**2 * sigma_mm**2 * frequency**2),\n",
|
||||
" lw=1.6, color=colours[name], label=f\"{name} ({r['mtf50']:.0f} lp/mm)\")\n",
|
||||
"ax[0].set_xlim(-9, 9); ax[0].set_ylim(-0.05, 1.35)\n",
|
||||
"ax[0].set_xlabel(r'position across the edge [$\\mu$m]')\n",
|
||||
"ax[0].set_ylabel('relative intensity')\n",
|
||||
"ax[0].legend(fontsize=8); ax[0].grid(alpha=.3); ax[0].set_title('oversampled ESF')\n",
|
||||
"ax[1].axvline(200, color='k', ls=':', lw=.8, label='2.5 um Nyquist')\n",
|
||||
"ax[1].axhline(0.5, color='grey', lw=.5)\n",
|
||||
"ax[1].set_xlim(0, 400); ax[1].set_ylim(0, 1.05)\n",
|
||||
"ax[1].set_xlabel('spatial frequency [lp/mm]'); ax[1].set_ylabel('MTF')\n",
|
||||
"ax[1].legend(fontsize=8); ax[1].grid(alpha=.3); ax[1].set_title('MTF from the fitted ESF')\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "61548cb0",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3. Where the GridBased sub-pixel phase stands\n",
|
||||
"\n",
|
||||
"Under the uniform illumination of the flat field the reconstructed positions\n",
|
||||
"should fill the pixel evenly; the Rosenblatt remap in\n",
|
||||
"`05_infer_measurement.py` makes them do so."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "79ecd95a",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:54.251748Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:54.251666Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:54.735190Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:54.734959Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1650x462 with 5 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"before = np.load(GRID / FLAT_RUN / 'subpixel_phase_before.npy')\n",
|
||||
"after = np.load(GRID / FLAT_RUN / 'subpixel_phase_after.npy')\n",
|
||||
"\n",
|
||||
"fig, axes = plt.subplots(1, 3, figsize=(15, 4.2))\n",
|
||||
"for ax, histogram, title in ((axes[0], before, 'before flattening'),\n",
|
||||
" (axes[1], after, 'after flattening')):\n",
|
||||
" im = ax.imshow(histogram.T / histogram.mean(), origin='lower', extent=[0, 1, 0, 1],\n",
|
||||
" vmin=0.9, vmax=1.1, cmap='viridis')\n",
|
||||
" ax.set_title(f'flat field, {title}', fontsize=10)\n",
|
||||
" ax.set_xlabel('sub-pixel x'); ax.set_ylabel('sub-pixel y')\n",
|
||||
" plt.colorbar(im, ax=ax, fraction=0.046)\n",
|
||||
"for histogram, title in ((before, 'before'), (after, 'after')):\n",
|
||||
" profile = histogram.sum(axis=1)\n",
|
||||
" axes[2].plot(np.linspace(0, 1, len(profile)), profile / profile.mean(), lw=1, label=title)\n",
|
||||
"axes[2].axhline(1, color='k', lw=.6); axes[2].set_xlabel('sub-pixel x')\n",
|
||||
"axes[2].set_ylabel('relative density'); axes[2].legend(); axes[2].grid(alpha=.3)\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "5dc0762d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4. Relative DQE"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "5e11e1e3",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:54.736713Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:54.736582Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:54.840950Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:54.840626Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"variant QE rel MTF(200) DQE rel (relative to cluster <=3ph)\n",
|
||||
"eta 0.855 0.170 0.025\n",
|
||||
"cluster 1ph 0.855 0.225 0.043\n",
|
||||
"cluster <=2ph 0.981 0.221 0.048\n",
|
||||
"cluster <=3ph 1.000 0.229 0.052\n",
|
||||
"GridBased flat 1.014 0.252 0.064\n",
|
||||
"\n",
|
||||
"highest relative DQE at 200 lp/mm: GridBased flat (1.23x the cluster <=3ph chain, 2.60x eta)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# DQE(f) is proportional to QE * MTF(f)^2. Every chain sees the same beam, so\n",
|
||||
"# the ratio of detected photons is the ratio of QE and the relative DQE is well\n",
|
||||
"# defined even without the absolute incident flux.\n",
|
||||
"def mtf_at(frequency_lpmm, sigma_gauss_um):\n",
|
||||
" sigma_mm = sigma_gauss_um / 1000.0\n",
|
||||
" return float(np.exp(-2 * np.pi**2 * sigma_mm**2 * frequency_lpmm**2))\n",
|
||||
"\n",
|
||||
"FREQUENCY = 200.0 # lp/mm, the Nyquist of the 2.5 um bins\n",
|
||||
"reference_photons = results['cluster <=3ph']['photons']\n",
|
||||
"print(f\"{'variant':16s} {'QE rel':>8} {'MTF(200)':>9} {'DQE rel':>9} \"\n",
|
||||
" f\"(relative to cluster <=3ph)\")\n",
|
||||
"relative_dqe = {}\n",
|
||||
"for name, r in results.items():\n",
|
||||
" qe = r['photons'] / reference_photons\n",
|
||||
" mtf200 = r['mtf200_lsf'] # measured from the LSF, as in the poly notebook\n",
|
||||
" relative_dqe[name] = qe * mtf200**2\n",
|
||||
" print(f'{name:16s} {qe:8.3f} {mtf200:9.3f} {relative_dqe[name]:9.3f}')\n",
|
||||
"best = max(relative_dqe, key=relative_dqe.get)\n",
|
||||
"print(f\"\\nhighest relative DQE at {FREQUENCY:.0f} lp/mm: {best} \"\n",
|
||||
" f\"({relative_dqe[best]/relative_dqe['cluster <=3ph']:.2f}x the cluster <=3ph chain, \"\n",
|
||||
" f\"{relative_dqe[best]/relative_dqe['eta']:.2f}x eta)\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a0cbe193",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 5. Summary"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "72edb58e",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:54.842114Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:54.842030Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:54.948033Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:54.947608Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{\n",
|
||||
" \"eta\": {\n",
|
||||
" \"sigma_um\": 1.5357788997826887,\n",
|
||||
" \"sigma_err_um\": 0.018934140987143105,\n",
|
||||
" \"mtf50_lsf_lpmm\": 127.41391534878392,\n",
|
||||
" \"mtf200_lsf\": 0.16986274278517122,\n",
|
||||
" \"chi2_ndf\": 1.0632259342404946,\n",
|
||||
" \"mtf50_lpmm\": 122.01666864663473,\n",
|
||||
" \"mtf10_lpmm\": 222.38949945174375,\n",
|
||||
" \"rows_kept\": 1.0,\n",
|
||||
" \"photons\": 160989360.0\n",
|
||||
" },\n",
|
||||
" \"cluster 1ph\": {\n",
|
||||
" \"sigma_um\": 1.3553236105888296,\n",
|
||||
" \"sigma_err_um\": 0.015582837583920595,\n",
|
||||
" \"mtf50_lsf_lpmm\": 140.72272920365313,\n",
|
||||
" \"mtf200_lsf\": 0.22534741293893693,\n",
|
||||
" \"chi2_ndf\": 0.6948283846340041,\n",
|
||||
" \"mtf50_lpmm\": 138.26264344931204,\n",
|
||||
" \"mtf10_lpmm\": 251.999668656873,\n",
|
||||
" \"rows_kept\": 1.0,\n",
|
||||
" \"photons\": 160989340.0\n",
|
||||
" },\n",
|
||||
" \"cluster <=2ph\": {\n",
|
||||
" \"sigma_um\": 1.380244936199657,\n",
|
||||
" \"sigma_err_um\": 0.016190473494226774,\n",
|
||||
" \"mtf50_lsf_lpmm\": 138.11611497098744,\n",
|
||||
" \"mtf200_lsf\": 0.2208935552975036,\n",
|
||||
" \"chi2_ndf\": 0.8064499904260305,\n",
|
||||
" \"mtf50_lpmm\": 135.76621091995148,\n",
|
||||
" \"mtf10_lpmm\": 247.44963146296,\n",
|
||||
" \"rows_kept\": 1.0,\n",
|
||||
" \"photons\": 184639952.0\n",
|
||||
" },\n",
|
||||
" \"cluster <=3ph\": {\n",
|
||||
" \"sigma_um\": 1.381207746488057,\n",
|
||||
" \"sigma_err_um\": 0.016615366693369205,\n",
|
||||
" \"mtf50_lsf_lpmm\": 136.79352035267127,\n",
|
||||
" \"mtf200_lsf\": 0.22868136720959276,\n",
|
||||
" \"chi2_ndf\": 0.8533928535430366,\n",
|
||||
" \"mtf50_lpmm\": 135.6715712069733,\n",
|
||||
" \"mtf10_lpmm\": 247.2771396335164,\n",
|
||||
" \"rows_kept\": 1.0,\n",
|
||||
" \"photons\": 188275709.0\n",
|
||||
" },\n",
|
||||
" \"GridBased flat\": {\n",
|
||||
" \"sigma_um\": 1.3596210744597628,\n",
|
||||
" \"sigma_err_um\": 0.018755935321852032,\n",
|
||||
" \"mtf50_lsf_lpmm\": 140.32690640620402,\n",
|
||||
" \"mtf200_lsf\": 0.2518136955393898,\n",
|
||||
" \"chi2_ndf\": 1.104983605454407,\n",
|
||||
" \"mtf50_lpmm\": 137.8256255727252,\n",
|
||||
" \"mtf10_lpmm\": 251.20315300123687,\n",
|
||||
" \"rows_kept\": 0.9956521739130435,\n",
|
||||
" \"photons\": 190825531.0\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"written to /mnt/sls_det_storage/moench_data/MLXID/InferenceResults/GridBased/Edge_3filters_pos0_12keV/knife_edge_comparison.json\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"summary = {\n",
|
||||
" 'measurement': 'Edge/Flat_3filters_pos0_12keV',\n",
|
||||
" 'roi_superpixel': list(ROI),\n",
|
||||
" 'bin_um': BIN_UM,\n",
|
||||
" 'bin_width_um': BIN_WIDTH_UM,\n",
|
||||
" 'convention': 'sigma = ODR p2 (Gaussian LSF); MTF50 = 1000 sqrt(ln 2 / 2) / (pi sigma); '\n",
|
||||
" 'ESF from DeepLearning/src, bin width 0.3 um',\n",
|
||||
" 'grid_model_epoch': grid_summary['epoch'],\n",
|
||||
" 'grid_frames': grid_summary['n_frames'],\n",
|
||||
" 'occupancy_percent': occupancy * 100, # flat field, ESF ROI\n",
|
||||
" 'grid_subpixel_before': grid_summary['subpixel_nonuniformity_before'],\n",
|
||||
" 'grid_subpixel_after': grid_summary['subpixel_nonuniformity_after'],\n",
|
||||
" 'variants': {name: dict(sigma_um=float(r['sigma']), sigma_err_um=float(r['sigma_err']),\n",
|
||||
" mtf50_lsf_lpmm=float(r['mtf50_lsf']),\n",
|
||||
" mtf200_lsf=float(r['mtf200_lsf']),\n",
|
||||
" chi2_ndf=float(r['chi2_ndf']),\n",
|
||||
" mtf50_lpmm=float(r['mtf50']), mtf10_lpmm=float(r['mtf10']),\n",
|
||||
" rows_kept=float(r['rows_kept']),\n",
|
||||
" photons=float(r['photons']))\n",
|
||||
" for name, r in results.items()},\n",
|
||||
" 'relative_dqe_200lpmm': relative_dqe,\n",
|
||||
"}\n",
|
||||
"print(json.dumps(summary['variants'], indent=1))\n",
|
||||
"out = GRID / EDGE_RUN / 'knife_edge_comparison.json'\n",
|
||||
"json.dump(summary, open(out, 'w'), indent=1)\n",
|
||||
"print(f'\\nwritten to {out}')"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "pytorch_nightly",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.18"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,897 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b3ef09b8",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Knife edge, 12 keV, MOENCH040 — polychromatic 2–20 keV GridBased model\n",
|
||||
"\n",
|
||||
"The polychromatic GridBased network retrained for the 650 µm **MOENCH040** on\n",
|
||||
"flat **2–20 keV** frames (`[32, 64, 96, 96]`, α(E,t)/β(E,t) charge-cloud table of\n",
|
||||
"MOENCH040 @150 V), run over the same 2603 MaxIV knife-edge scan as the 12 keV\n",
|
||||
"monochromatic model: four flux points (0–3 filters), edge and flat field each.\n",
|
||||
"Reconstruction settings are those of the 12 keV runs (same ROI readout,\n",
|
||||
"pedestal, column common mode, self-flattening); the only difference is the model\n",
|
||||
"(and FP16 with an FP32 head, as for every poly model).\n",
|
||||
"\n",
|
||||
"**Edge width.** The ESF and its fit are the ones of `Plotting/fig_knife_edge.py\n",
|
||||
"--fit odr`: `generate_presampled_esf()` and `get_odr_fitting()` from\n",
|
||||
"`DeepLearning/src/funcs_postprocess.py`, ROI `(330, 465, 260, 490)` on the\n",
|
||||
"990 × 990 super-frame, symmetric ±4σ window, **ESF bin width 0.3 µm**. The ODR\n",
|
||||
"model is `p0/2 · (1 + erf((x − p1)/(√2 σ))) + p3`, so the fit gives **σ**, the\n",
|
||||
"width of the Gaussian LSF, which is what the tables quote, with\n",
|
||||
"**MTF50 = 1000 √(ln2 / 2) / (π σ) lp/mm** (the Gaussian's), plus MTF50 and\n",
|
||||
"MTF(200 lp/mm) measured from the LSF by FFT with the first-crossing and\n",
|
||||
"central-difference corrections of `Plotting/knife_edge_numbers.py`. Only the\n",
|
||||
"flattened GridBased reconstructions are analysed.\n",
|
||||
"\n",
|
||||
"**Occupancy** is that of the flat field inside the ESF ROI: the reconstructed\n",
|
||||
"photons per 25 µm pixel per frame over `ROI // 10`, the pixels over which\n",
|
||||
"`DeepLearning/Notebooks/KnifeEdge_3filters_pos0.ipynb` sums the deposited energy.\n",
|
||||
"The flux points are labelled with the 12 keV model's value, as in the\n",
|
||||
"single-flux notebooks.\n",
|
||||
"\n",
|
||||
"The 12 keV model's images are re-fitted here with the same code, and so are the\n",
|
||||
"2026-09-17 GridBased knife-edge notebooks since 2026-09-28: the numbers agree\n",
|
||||
"digit for digit with `KnifeEdge_{0,1,2,3}filters*.ipynb`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "4d16f0f1",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:35.617146Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:35.616976Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:37.557915Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:37.557583Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Welcome to JupyROOT 6.28/10\n",
|
||||
"poly model : 260927_poly2to20keV_Moench040_c96_00 tag 'poly2to20'\n",
|
||||
"12 keV model: 260831_12keV_Moench040_01\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import json\n",
|
||||
"import os\n",
|
||||
"import sys\n",
|
||||
"from pathlib import Path\n",
|
||||
"\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import numpy as np\n",
|
||||
"from scipy.optimize import curve_fit\n",
|
||||
"\n",
|
||||
"sys.path.insert(0, '/home/xie_x1/MLXID/DeepLearning/src') # the code Plotting/ uses\n",
|
||||
"sys.path.insert(0, '/home/xie_x1/MLXID/Plotting')\n",
|
||||
"from ROOT import gROOT\n",
|
||||
"gROOT.SetBatch(True)\n",
|
||||
"from funcs_postprocess import generate_presampled_esf, get_odr_fitting\n",
|
||||
"from knife_edge_numbers import mtf as mtf_from_lsf # first crossing, sinc-corrected\n",
|
||||
"\n",
|
||||
"GRID = Path('/mnt/sls_det_storage/moench_data/MLXID/InferenceResults/GridBased')\n",
|
||||
"PUBLISHED = Path('/home/xie_x1/MLXID/DeepLearning/InferenceResults')\n",
|
||||
"ETA = Path('/home/xie_x1/MLXID/EtaInterpolation/Results')\n",
|
||||
"GRIDBASED = Path('/home/xie_x1/MLXID/GridBased')\n",
|
||||
"OVERNIGHT = GRIDBASED / 'Results/overnight_poly2to20keV_Moench040'\n",
|
||||
"\n",
|
||||
"POLY_TAG = os.environ.get('GRID_POLY_TAG', 'poly2to20')\n",
|
||||
"POLY_EXPERIMENT = GRIDBASED / (os.environ.get('GRID_POLY_EXPERIMENT')\n",
|
||||
" or (OVERNIGHT / 'state/experiment').read_text().strip())\n",
|
||||
"MONO_EXPERIMENT = GRIDBASED / 'Results/260831_12keV_Moench040_01'\n",
|
||||
"\n",
|
||||
"BIN_UM = 2.5 # super-pixel = 25 um / 10\n",
|
||||
"ROI = (330, 465, 260, 490) # x1, x2, y1, y2 on the 990 x 990 frame, as published\n",
|
||||
"CROP = 10 # 1010 -> 990\n",
|
||||
"BIN_WIDTH_UM = 0.3 # presampled ESF bin\n",
|
||||
"N_SIGMA = 4.0 # symmetric ODR window\n",
|
||||
"FLUX = [('3filters_pos0', '3 filters'), ('2filters', '2 filters'),\n",
|
||||
" ('1filters', '1 filter'), ('0filters', '0 filters')]\n",
|
||||
"MONO, POLY = 'GridBased 12 keV', 'GridBased 2-20 keV'\n",
|
||||
"\n",
|
||||
"plt.rcParams.update({'figure.dpi': 110, 'image.cmap': 'gray', 'image.origin': 'lower',\n",
|
||||
" 'image.interpolation': 'nearest'})\n",
|
||||
"print('poly model :', POLY_EXPERIMENT.name, ' tag', repr(POLY_TAG))\n",
|
||||
"print('12 keV model:', MONO_EXPERIMENT.name)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3b2ee3ef",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1. The reconstructions"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "aeb7d57f",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:37.559180Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:37.559038Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:40.056391Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:40.056105Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"missing: nothing\n",
|
||||
"\n",
|
||||
"flux point occupancy model own occ. frames edge photons flat photons frame/s sub-pixel rms\n",
|
||||
"3 filters 0.75% GridBased 2-20 keV 0.76% 14,000,000 1.9590e+08 3.3831e+08 7603 23.4 -> 3.1 %\n",
|
||||
"3 filters 0.75% GridBased 12 keV 0.75% 14,000,000 1.9083e+08 3.3060e+08 7647 22.6 -> 4.3 %\n",
|
||||
"2 filters 1.81% GridBased 2-20 keV 1.85% 7,000,000 2.3612e+08 4.1102e+08 7664 22.2 -> 2.8 %\n",
|
||||
"2 filters 1.81% GridBased 12 keV 1.81% 7,000,000 2.3053e+08 4.0162e+08 7123 21.6 -> 3.9 %\n",
|
||||
"1 filter 4.45% GridBased 2-20 keV 4.58% 7,000,000 5.8278e+08 1.0097e+09 7682 20.0 -> 2.2 %\n",
|
||||
"1 filter 4.45% GridBased 12 keV 4.45% 7,000,000 5.6697e+08 9.8283e+08 6537 19.8 -> 3.0 %\n",
|
||||
"0 filters 10.77% GridBased 2-20 keV 11.15% 3,500,000 7.0822e+08 1.2280e+09 7185 18.6 -> 1.3 %\n",
|
||||
"0 filters 10.77% GridBased 12 keV 10.77% 3,500,000 6.8684e+08 1.1910e+09 6176 18.3 -> 1.6 %\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def crop(image):\n",
|
||||
" return image[CROP:-CROP, CROP:-CROP] if image.shape[0] == 1010 else image\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def run_dir(run, tag):\n",
|
||||
" return GRID / (run + (f'_{tag}' if tag else ''))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def summary_of(run, tag):\n",
|
||||
" path = run_dir(run, tag) / 'summary.json'\n",
|
||||
" return json.load(open(path)) if path.exists() else None\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def grid_pair(filters, tag, flattened):\n",
|
||||
" name = 'binned_image_flattened.npy' if flattened else 'binned_image.npy'\n",
|
||||
" edge, flat = run_dir(f'Edge_{filters}_12keV', tag), run_dir(f'Flat_{filters}_12keV', tag)\n",
|
||||
" if not ((edge / name).exists() and (flat / name).exists()):\n",
|
||||
" return None\n",
|
||||
" return crop(np.load(edge / name).astype(float)), crop(np.load(flat / name).astype(float))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"ETA_FILES = {'3filters_pos0': ('2603MaxIV_Edge3Filters_pos0_12keV_fromClusters.npy',\n",
|
||||
" '2603MaxIV_FlatField3Filters_pos0_12keV_fromClusters.npy'),\n",
|
||||
" '2filters': ('2603MaxIV_Edge2Filters_12keV_fromClusters.npy',\n",
|
||||
" '2603MaxIV_Flat2Filters_12keV_fromClusters.npy'),\n",
|
||||
" '1filters': ('2603MaxIV_Edge1Filters_12keV_fromClusters.npy',\n",
|
||||
" '2603MaxIV_Flat1Filters_12keV_fromClusters.npy')}\n",
|
||||
"CNN = {1: '1ph_260512_12keV_v260511_06', 2: '2ph_260610_12keV_v260610_01',\n",
|
||||
" 3: '3ph_260611_12keV_v260611_00'}\n",
|
||||
"CNN_DIRS = {'3filters_pos0': ('KnifeEdge_3filters_pos0', 'FlatField_3filters_pos0'),\n",
|
||||
" '2filters': ('KnifeEdge_2filters', 'FlatField_2filters')}\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def cnn_pair(filters, up_to):\n",
|
||||
" knife_dir, flat_dir = CNN_DIRS[filters]\n",
|
||||
" edge = flat = 0\n",
|
||||
" for n in range(1, up_to + 1):\n",
|
||||
" name = f'{n}Photon_ML_superFrame_etaInterpolated.npy'\n",
|
||||
" edge = edge + crop(np.load(PUBLISHED / knife_dir / CNN[n] / 'augX1' / name).astype(float))\n",
|
||||
" flat = flat + crop(np.load(PUBLISHED / flat_dir / CNN[n] / 'augX1' / name).astype(float))\n",
|
||||
" return edge, flat\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"variants, missing = {}, []\n",
|
||||
"for filters, label in FLUX:\n",
|
||||
" v = {}\n",
|
||||
" for name, tag, flattened in ((f'{POLY}, flattened', POLY_TAG, True),\n",
|
||||
" (f'{MONO}, flattened', '', True)):\n",
|
||||
" pair = grid_pair(filters, tag, flattened)\n",
|
||||
" if pair is None:\n",
|
||||
" missing.append(f'{label}: {name}')\n",
|
||||
" else:\n",
|
||||
" v[name] = pair\n",
|
||||
" if filters in ETA_FILES:\n",
|
||||
" v['eta'] = tuple(np.load(ETA / f).astype(float) for f in ETA_FILES[filters])\n",
|
||||
" if filters in CNN_DIRS:\n",
|
||||
" for n in (1, 2, 3):\n",
|
||||
" v[f'cluster CNN <={n}ph'] = cnn_pair(filters, n)\n",
|
||||
" variants[filters] = v\n",
|
||||
"\n",
|
||||
"def flat_occupancy(filters, tag):\n",
|
||||
" # reconstructed photons per 25 um pixel per frame in the flat field, inside the\n",
|
||||
" # ESF ROI: ROI // 10 in pixels of the 99 x 99 frame, both ends included as in\n",
|
||||
" # DeepLearning/Notebooks; +1 because the 101 x 101 frame is cropped by 1 px\n",
|
||||
" run = run_dir(f'Flat_{filters}_12keV', tag)\n",
|
||||
" if not (run / 'native_image.npy').exists():\n",
|
||||
" return np.nan\n",
|
||||
" native = np.load(run / 'native_image.npy') / json.load(open(run / 'summary.json'))['n_frames']\n",
|
||||
" x0, x1, y0, y1 = (v // 10 for v in ROI)\n",
|
||||
" return float(native[y0 + 1:y1 + 2, x0 + 1:x1 + 2].mean())\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# the flux point is labelled with the 12 keV model's value, the same number as in\n",
|
||||
"# KnifeEdge_{0,1,2,3}filters*.ipynb; the 2-20 keV model counts 2-3 % more photons\n",
|
||||
"occupancy = {f: flat_occupancy(f, '') for f, _ in FLUX}\n",
|
||||
"print('missing:', missing or 'nothing')\n",
|
||||
"print(f\"\\n{'flux point':10s} {'occupancy':>9s} {'model':20s} {'own occ.':>8s} {'frames':>11s} {'edge photons':>13s} \"\n",
|
||||
" f\"{'flat photons':>13s} {'frame/s':>8s} {'sub-pixel rms':>14s}\")\n",
|
||||
"for filters, label in FLUX:\n",
|
||||
" for model, tag in ((POLY, POLY_TAG), (MONO, '')):\n",
|
||||
" e, f = summary_of(f'Edge_{filters}_12keV', tag), summary_of(f'Flat_{filters}_12keV', tag)\n",
|
||||
" if e is None or f is None:\n",
|
||||
" continue\n",
|
||||
" print(f\"{label:10s} {occupancy[filters]*100:8.2f}% {model:20s} {flat_occupancy(filters, tag)*100:7.2f}% \"\n",
|
||||
" f\"{e['n_frames']:11,d} \"\n",
|
||||
" f\"{e['n_photons']:13.4e} {f['n_photons']:13.4e} {e['frames_per_second']:8.0f} \"\n",
|
||||
" f\"{f['subpixel_nonuniformity_before']*100:5.1f} -> {f['subpixel_nonuniformity_after']*100:4.1f} %\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "c5b40483",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:40.057689Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:40.057511Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:40.832086Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:40.831793Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAABwQAAAN7CAYAAABLVi50AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AAEAAElEQVR4nOy9d5hV1dn+f5/pM+dMoWMFK6CiEhUECwQVgw0sEbGB8bXEXmNLRP1pfC2xt2gU29eaCFGDGEVRg71gsKBRsQZUFKb32b8/eO917r1mnzNnYICZ4flc11zM7LPL2msf1r2ftlYsCIIAhmEYhmEYhmEYhmEYhmEYhmEYhmF0S7LWdgMMwzAMwzAMwzAMwzAMwzAMwzAMw1h9WEDQMAzDMAzDMAzDMAzDMAzDMAzDMLoxFhA0DMMwDMMwDMMwDMMwDMMwDMMwjG6MBQQNwzAMwzAMwzAMwzAMwzAMwzAMoxtjAUHDMAzDMAzDMAzDMAzDMAzDMAzD6MZYQNAwDMMwDMMwDMMwDMMwDMMwDMMwujEWEDQMwzAMwzAMwzAMwzAMwzAMwzCMbowFBA3DMAzDMAzDMAzDMAzDMAzDMAyjG2MBQcMwDMMwDMMwDMMwDMMwDMMwDMPoxlhA0DAMwzAMwzAMwzAMwzAMwzAMwzC6MRYQNAzDMAzDMNZ57r33XsRiMcydO7dDzzt37lzEYjHce++9oe01NTU47bTTsPHGGyM7OxsDBw7s0Ot2BGPGjOmU7TJSk+r7lopLLrkEsVgMX3755Wpt15qkvd/bNdEHAwcOxJgxY1bb+Q3DMAzDMAzDMDLBAoKGYRiGYRiGsYa56qqrcPPNN2PSpEm49957ccMNN6ztJnUp/vOf/+CSSy7BLrvsgv79+yMej2OrrbbCaaedhsWLF2d8HgaDon7OOeec1XgHxppk5syZuOSSS1brNS655BLMnDlztV4jU7788suU32v++MkP8+bNw4EHHohNN90UBQUF6NOnD7bbbjuccMIJeO+990L7pjvv//zP/7TZvjFjxoSOycnJQb9+/TBx4kS8+uqrKY9rbGzEnXfeidGjR6NXr17Iz8/HRhtthMmTJ+ONN95Iea2cnJy2O80wDMMwDMMw1gHszdgwDMMwDMMwVhO77747amtrkZubG9r+3HPPYejQobjmmmvWUsu6NnfffTduuukm7Lvvvvj1r3+NoqIivP7667jtttvw//7f/8O8efMwePDgjM93/fXXo3fv3qFtW221VUc3u9Px+9//Hueffz7y8/PXdlM6jH/+858IgiC0bebMmbjvvvtWa1Dw0ksvxZQpUzBx4sTVdo32MmbMGBx77LGRnw0ZMsT9/uc//xknnngi+vfvj6OPPhqbb745li9fjoULF+KJJ57AFltsgWHDhoWO33rrrXH++ee3Ou/mm2+eUduysrJw3333AQDq6+vxwQcf4K677sKsWbMwZ84c7LbbbqH9ly5div333x+vv/46dt11V1xwwQXo0aMHPvvsM9x///145JFHcNlll+EPf/hDRtc3DMMwDMMwjHURCwgahmEYhmEYxmoiKysLBQUFrbYvWbIEG2+88VpoUffgkEMOwXnnnYcePXq4bccffzx23nlnnHDCCbj44ovx2GOPZXy+iRMnrpPTo+bk5HS76qm8vLy13YROw2abbYYjjzwy7T5NTU244IILkEgk8NZbb2HDDTcMfd7Y2Iiff/651XH9+/dv89zpiMVirY4fPXo0DjzwQFx99dWtAoKTJk3C66+/jmuvvRZnn3126LMLL7wQ++67Ly6++GIMHDgQRx111Eq3yzAMwzAMwzC6MzZlqGEYhmEYhmGk4Pbbb0dOTg4OPfRQ1NfXA0iuB/bpp59iwoQJKC0tRSKRwL777ovPP/88dLy/phunqFy0aBFeeuklN2WeVi699957OOSQQ9C3b1/k5eVh0003xfnnn4+ampqM2/35559j6tSpWH/99ZGXl4cNN9wQJ510EpYuXdpq388++wwHHnggSktLUVxcjHHjxuH9999Pee4HHngA2267LfLz87Hhhhvid7/7HT7++ONW9wEAQRDgrrvuwvDhwxGPxxGPxzFq1KhVnlpxxx13DAUDyWGHHQYA+Pe//93uc1ZWVqKxsbHdx6Vbgy5qPTt+fz744APsvffeKCkpQa9evfA///M/qK6uRhAEuOaaa7D55psjPz8fW2+9Nf7xj3+0u1233347hgwZgoKCAgwcOBCXXXYZmpqa2mw7t3366ae4+OKLMWDAAOTn52PIkCF46KGHWl1n9uzZGDt2LPr27YuCggJsuOGG2GeffdJO/ZiO4447Djk5OVi+fLnb9t///tf9X9EpYZcvX47s7GycdNJJbpvf5wMHDnSVaDpNpb/OYkNDQ0b368P/4wBw3333ha7hk8mYwbZcffXV2HbbbVFYWIiSkhLsueeeePnll9tsT3tZunQpli1bhkGDBrUKBgJAbm4u+vXr1+HXjWLPPfcEsGJKYGXWrFl44YUXMGHChFbBQAAoLi7Go48+isLCQlxwwQUr9f/YMAzDMAzDMNYFulc6qGEYhmEYhmF0AEEQ4IILLsBVV12FM888E3/6059CDv7vvvsOu+++Ow444ABcddVV+M9//oObb74ZBxxwABYsWICsrOi8u4MOOgibb745zjzzTPTu3RsXXXQRAGDbbbcFsCK4MnHiRGy00UY49dRT0a9fP7z//vu47rrrMG/ePLz44ottVnTNnz8fY8aMQVFREX7zm99gwIAB+M9//oPbb78dc+bMwZtvvonS0lIAwDfffINRo0Zh+fLlOPHEEzFkyBC89tprGDNmDHr16tXq3LfeeitOOeUUDB48GJdeeilyc3Px8MMPt1qPjBxzzDG4//77MWHCBBxxxBEAgCeeeAIHHnggbr/9dpx44onpH0Q7+e677wAAffv2bddx2223HSoqKpCVlYVhw4bhd7/7HQ499NAObZvy3XffYezYsTjkkENw4IEH4rXXXsPdd9+N2tpa9OjRA//6179wwgknIDs7GzfeeCMOOuggfPrppxgwYEBG57/lllvw7bff4sQTT0TPnj0xY8YMTJs2DV988UWrQFgqpkyZglgshtNOOw1ZWVm47bbbcMQRR2DTTTfFzjvvDAB4+eWXsd9++2GrrbbCueeei169emHJkiWYN28e5s+fj1GjRrW7b/bcc0/85S9/wYsvvogDDzwQADBnzhz3/+/55593FWAvvvgiWlpasMcee6Q83w033IDrrrsOr7zyCh544AG33W9bJvcbxZAhQ/DAAw/gqKOOwm677Ybjjz8+cr9Mx4ympibss88+eOmllzB58mSceOKJqKmpwYMPPoixY8di5syZ2G+//TLoyRVTcUYlAcRiMff/u1+/fkgkEvjwww/x6quvZvzMGhsbI8/tT73bHj777DMAaDX2PP744wCA3/72tymPXW+99TBx4kQ8/PDDeO2117D77ruvdDsMwzAMwzAMo9sSGIZhGIZhGMY6zvTp0wMAwYsvvhjU1dUFhx12WJCVlRXceOONrfYdMGBAACB46KGHQtuvvPLKAEDw7LPPum0vvvhiACCYPn16q3OMHj06tK22tjbo379/MHz48KCuri702eOPPx4ACO69994272X77bcPNtlkk+Cnn34KbX/99deDrKys4JJLLnHbjjrqqABAMGPGjMh7GTBggNu2bNmyIB6PB5tuumlQUVHhttfV1QU77bRTACCYNm2a2z5z5swAQHDddde1auN+++0XlJSUhM7TERx00EGR/Z2K66+/Pvif//mfYPr06cGTTz4Z/OlPf3LP98orr8zoHNOmTQsABIsWLWr12ejRo0N9GATJ78/DDz8c2j5hwoQgFosF22+/fVBfX++2v/feewGA4IILLmizLfy+FRUVBV9++aXb3tzcHOy///4BgOCVV15J23ZuGz9+fNDc3Oy2f/3110Fubm4wefJkt+3MM88MAARLlixps22Z8sMPPwSxWCw46aST3LYpU6YE2223XbDtttsGRx99tNt+8sknB1lZWaHvelSfT5kyJUhl+rbnftMBIJgyZUrkZ+0ZM2644YYAQPDEE0+E9m1oaAiGDRsWbLLJJm22ZdGiRQGAlD/Z2dmh/a+//nr32XbbbReccsopwX333Rd8/fXXKe811U9tbW2b7Rs9enSQnZ0d/Pjjj8GPP/4YfPvtt8Hs2bODbbbZJgAQ3HHHHaH9d9hhhwBAqzHN59prrw0ABDfffHOraxmGYRiGYRiGEQQ2ZahhGIZhGIZh/B/Lli3DuHHjMHPmTDz++OM47bTTIvdbf/31MXny5NC2vfbaC8CKaQFXhueffx5LlizB1KlTUVlZiaVLl7qf0aNHIx6P49lnn017jg8++ADz58/HYYcdhpaWltA5NttsM2yxxRbuHC0tLZg5cya22morTJw4MXSeM844A4lEIrTtn//8J6qrq3HSSSehuLjYbc/Pz8eZZ57Zqi0PPPAACgsLMWnSpFA7li5digMPPBAVFRV47bXXVqqvovjjH/+IJ554AhMnTsSUKVMyOuaMM87AXXfdhalTp2L//ffHWWedhQULFmDTTTfFxRdfjG+//bbD2qesv/76bnpTMnr0aARBgJNOOim0Dt7222+PkpKSdn2vjjzyyFA1YVZWFs4//3wAwN/+9reMznHmmWeGKl032mgjDBo0KNSOsrIyACsquPzpSFeWPn36YOjQoZgzZ47bNmfOHOyxxx7YY489Wm3ffvvt0bNnz1W+bib3uypkOmY88MADGDhwIHbbbbfQ/5ny8nIccMABWLRoUcZtGj9+PJ577rlWP//85z9D+51xxhmYNWsW9t9/fyxatAi33HILpkyZggEDBuDggw/GTz/91Orcw4YNizx3pms4Njc3o0+fPujTpw823HBD/OpXv8J///tfXH/99TjhhBNC+5aXlwOAq2xOBT/n/oZhGIZhGIZLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1848x902 with 8 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"shown = [(f, l) for f, l in FLUX if f'{POLY}, flattened' in variants[f]]\n",
|
||||
"fig, axes = plt.subplots(2, max(len(shown), 1), figsize=(4.2 * max(len(shown), 1), 8.2), squeeze=False)\n",
|
||||
"extent = [0, 990 * BIN_UM, 0, 990 * BIN_UM]\n",
|
||||
"for column, (filters, label) in enumerate(shown):\n",
|
||||
" for row, model in enumerate((MONO, POLY)):\n",
|
||||
" ax = axes[row, column]\n",
|
||||
" name = f'{model}, flattened'\n",
|
||||
" if name not in variants[filters]:\n",
|
||||
" ax.axis('off'); continue\n",
|
||||
" image = variants[filters][name][0]\n",
|
||||
" ax.imshow(image, extent=extent, vmax=np.percentile(image, 99.5))\n",
|
||||
" ax.add_patch(plt.Rectangle((ROI[0] * BIN_UM, ROI[2] * BIN_UM), (ROI[1] - ROI[0]) * BIN_UM,\n",
|
||||
" (ROI[3] - ROI[2]) * BIN_UM, edgecolor='red', facecolor='none', lw=1.2))\n",
|
||||
" ax.set_title(f'{label} ({occupancy[filters]*100:.2f} %)\\n{name}', fontsize=9)\n",
|
||||
" ax.set_xlabel('x [um]'); ax.set_ylabel('y [um]')\n",
|
||||
"fig.suptitle('knife edge, 2.5 um bins, with the ESF ROI')\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "19689795",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2. Edge spread function and ODR fit\n",
|
||||
"\n",
|
||||
"`generate_presampled_esf` fits an erf to every row of the ROI, fits a straight\n",
|
||||
"line through the edge positions, and resamples the knife/flat ratio onto a\n",
|
||||
"0.3 µm grid across the edge (bin content Σk/Σf). `get_odr_fitting` fits the ESF\n",
|
||||
"with x and y errors inside |x − p1| ≤ 4σ, iterating the window."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "02f502b8",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:40.833998Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:40.833910Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:45.700834Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:45.700450Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Final Edge Midpoint Fit: slope = -0.0871, intercept = 433.5999, chi2/ndf = 0.0389\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0860, intercept = 433.1036, chi2/ndf = 0.0451\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0866, intercept = 433.2062, chi2/ndf = 0.0458\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0859, intercept = 432.9570, chi2/ndf = 0.0451\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0858, intercept = 433.0080, chi2/ndf = 0.0419\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0859, intercept = 433.0672, chi2/ndf = 0.0473\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0855, intercept = 432.4900, chi2/ndf = 0.0377\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0858, intercept = 432.5887, chi2/ndf = 0.0361\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0858, intercept = 432.3990, chi2/ndf = 0.0751\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0854, intercept = 432.2740, chi2/ndf = 0.0576\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0855, intercept = 432.4402, chi2/ndf = 0.0479\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0850, intercept = 432.2537, chi2/ndf = 0.0406\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0853, intercept = 432.6611, chi2/ndf = 0.0386\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0852, intercept = 432.6254, chi2/ndf = 0.0434\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0859, intercept = 432.5449, chi2/ndf = 0.0615\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0860, intercept = 433.2953, chi2/ndf = 0.0337\n",
|
||||
"Final Edge Midpoint Fit: slope = -0.0858, intercept = 433.2022, chi2/ndf = 0.0302\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def analyse(edge, flat):\n",
|
||||
" esf = generate_presampled_esf(edge, flat, ROI, pixel_size_um=BIN_UM,\n",
|
||||
" bin_width_um=BIN_WIDTH_UM, chi2_threshold=15.0,\n",
|
||||
" residual_tolerance_px=1.0)\n",
|
||||
" n = esf['numpy']\n",
|
||||
" fit = get_odr_fitting(n['x'], n['z'], n['x_err'], n['z_err'], n_sigma=N_SIGMA)\n",
|
||||
" sigma, sigma_err = fit['sigma_um'], fit['sigma_err_um']\n",
|
||||
" try:\n",
|
||||
" mtf50_lsf, mtf200_lsf = mtf_from_lsf(dict(x=n['x'], z=n['z'], pars=fit['beta']))\n",
|
||||
" except Exception:\n",
|
||||
" mtf50_lsf = mtf200_lsf = np.nan\n",
|
||||
" return dict(x=n['x'], z=n['z'], z_err=n['z_err'], fit=fit,\n",
|
||||
" sigma=sigma, sigma_err=sigma_err,\n",
|
||||
" chi2_ndf=fit['chi2_ndf'], n_fit=int(fit['mask'].sum()),\n",
|
||||
" mtf50=1000 * np.sqrt(np.log(2) / 2) / (np.pi * sigma),\n",
|
||||
" mtf200=float(np.exp(-2 * np.pi**2 * (sigma / 1000)**2 * 200.0**2)),\n",
|
||||
" mtf50_lsf=mtf50_lsf, mtf200_lsf=mtf200_lsf,\n",
|
||||
" rows_kept=esf['valid_lines_ratio'], photons=float(edge.sum()))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"results = {}\n",
|
||||
"for filters, label in FLUX:\n",
|
||||
" results[filters] = {name: analyse(edge, flat) for name, (edge, flat) in variants[filters].items()}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "022aa946",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:45.702053Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:45.701965Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:45.805285Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:45.804879Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n",
|
||||
"=== 3 filters, occupancy 0.75 % (flat field, ESF ROI) ===\n",
|
||||
" sigma [um] chi2/ndf MTF50 [lp/mm] MTF50 LSF MTF(200) LSF edge photons\n",
|
||||
"GridBased 2-20 keV, flattened 1.420 +- 0.021 1.34 131.9 134.4 0.227 1.9590e+08\n",
|
||||
"GridBased 12 keV, flattened 1.360 +- 0.019 1.10 137.8 140.3 0.252 1.9083e+08\n",
|
||||
"eta 1.536 +- 0.019 1.06 122.0 127.4 0.170 1.6099e+08\n",
|
||||
"cluster CNN <=1ph 1.355 +- 0.016 0.69 138.3 140.7 0.225 1.6099e+08\n",
|
||||
"cluster CNN <=2ph 1.380 +- 0.016 0.81 135.8 138.1 0.221 1.8464e+08\n",
|
||||
"cluster CNN <=3ph 1.381 +- 0.017 0.85 135.7 136.8 0.229 1.8828e+08\n",
|
||||
"\n",
|
||||
"=== 2 filters, occupancy 1.81 % (flat field, ESF ROI) ===\n",
|
||||
" sigma [um] chi2/ndf MTF50 [lp/mm] MTF50 LSF MTF(200) LSF edge photons\n",
|
||||
"GridBased 2-20 keV, flattened 1.391 +- 0.018 1.00 134.7 139.8 0.254 2.3612e+08\n",
|
||||
"GridBased 12 keV, flattened 1.346 +- 0.019 1.15 139.2 143.8 0.259 2.3053e+08\n",
|
||||
"eta 1.483 +- 0.024 1.61 126.4 131.7 0.187 1.5670e+08\n",
|
||||
"cluster CNN <=1ph 1.352 +- 0.022 1.44 138.6 144.8 0.229 1.5670e+08\n",
|
||||
"cluster CNN <=2ph 1.372 +- 0.022 1.50 136.5 142.7 0.223 2.0504e+08\n",
|
||||
"cluster CNN <=3ph 1.386 +- 0.018 1.02 135.2 139.7 0.244 2.2076e+08\n",
|
||||
"\n",
|
||||
"=== 1 filter, occupancy 4.45 % (flat field, ESF ROI) ===\n",
|
||||
" sigma [um] chi2/ndf MTF50 [lp/mm] MTF50 LSF MTF(200) LSF edge photons\n",
|
||||
"GridBased 2-20 keV, flattened 1.551 +- 0.028 3.37 120.9 130.5 0.227 5.8278e+08\n",
|
||||
"GridBased 12 keV, flattened 1.388 +- 0.020 1.82 135.0 141.3 0.251 5.6697e+08\n",
|
||||
"eta 1.506 +- 0.023 1.83 124.4 130.0 0.218 2.3085e+08\n",
|
||||
"\n",
|
||||
"=== 0 filters, occupancy 10.77 % (flat field, ESF ROI) ===\n",
|
||||
" sigma [um] chi2/ndf MTF50 [lp/mm] MTF50 LSF MTF(200) LSF edge photons\n",
|
||||
"GridBased 2-20 keV, flattened 1.856 +- 0.037 7.36 101.0 113.1 0.173 7.0822e+08\n",
|
||||
"GridBased 12 keV, flattened 1.473 +- 0.017 1.30 127.2 133.0 0.222 6.8684e+08\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"header = (f\"{'':24s} {'sigma [um]':>16s} {'chi2/ndf':>8s} \"\n",
|
||||
" f\"{'MTF50 [lp/mm]':>13s} {'MTF50 LSF':>9s} {'MTF(200) LSF':>12s} {'edge photons':>13s}\")\n",
|
||||
"for filters, label in FLUX:\n",
|
||||
" print(f'\\n=== {label}, occupancy {occupancy[filters]*100:.2f} % (flat field, ESF ROI) ===')\n",
|
||||
" print(header)\n",
|
||||
" for name, r in results[filters].items():\n",
|
||||
" print(f\"{name:24s} {r['sigma']:7.3f} +- {r['sigma_err']:.3f} {r['chi2_ndf']:8.2f} \"\n",
|
||||
" f\"{r['mtf50']:13.1f} {r['mtf50_lsf']:9.1f} {r['mtf200_lsf']:12.3f} {r['photons']:13.4e}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "7b595528",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:45.806910Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:45.806826Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:46.448997Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:46.448709Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAAB4IAAAHKCAYAAADmRIbLAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AAEAAElEQVR4nOzdd3hT1eMG8Dfde5cCbWmZBQptaVmyoWxFhoBsUHCADEUFNyAqCMIPUXDgV5YKCojIkiEgIBsFZK8W2lI66J5pkvP7o+SSNEmbtmmblvfzPDyaO8495+bevL333CETQggQEREREREREREREREREVGNYVHVFSAiIiIiIiIiIiIiIiIiItNiRzARERERERERERERERERUQ3DjmAiIiIiIiIiIiIiIiIiohqGHcFERERERERERERERERERDUMO4KJiIiIiIiIiIiIiIiIiGoYdgQTEREREREREREREREREdUw7AgmIiIiIiIiIiIiIiIiIqph2BFMRERERERERERERERERFTDsCOYiIiIiIiIiIiIiIiIiKiGYUcwEREREREREREREREREVENw45gIiIiIiIiIiIiIiIiIqIahh3BREREREREREREREREREQ1DDuCiYiIiIgeY4cOHYJMJsOaNWsqpPwJEyZAJpNVSNlVITU1FV5eXli4cGFVV8XsrVmzBjKZDIcOHTJq+oreFtWOHTsGCwsLHD9+vEKXYwo1bf8xJDk5GePGjUPdunUhk8nQrVs3AJW3TRSntHUw1+3enHEdEBERERFVHHYEExERERFRlVN3BBT3Lzo6WmuexMREvPXWW2jZsiVcXFzg7OyMBg0aYPDgwfjf//5ndNk//PCD0fWcN28erK2tMX36dJ1xv/76K9q3bw9HR0e4u7tjwIABuHDhglHlJicn4/nnn0doaCg8PT1hZ2eHBg0aYOTIkTh//rzR9aOSdejQAX379sWrr74KIURVV8ekcnJysHjxYrRr1w5ubm7SdjRp0iRcuXJF7zxF9w9LS0u4uroiKCgIw4cPx08//QS5XF7ifDKZDA4ODmjZsiU+/PBD5ObmGl3v119/HT///DNefvllrF+/Hu+++67BaaOjozF37lycO3fO6PJNzRzqUNlUKhXat28PmUyGnj17VnV1iIiIiIjISFZVXQEiIiIiIiK1oUOHYuDAgXrHeXt7S/9/9+5d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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1936x462 with 4 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"colours = {f'{POLY}, flattened': '#c0392b', f'{MONO}, flattened': '#1f618d', 'eta': '#7d6608',\n",
|
||||
" 'cluster CNN <=1ph': '#7f8c8d', 'cluster CNN <=2ph': '#8e44ad', 'cluster CNN <=3ph': '#4a235a'}\n",
|
||||
"done = [(f, l) for f, l in FLUX if f'{POLY}, flattened' in results[f]]\n",
|
||||
"fig, axes = plt.subplots(1, max(len(done), 1), figsize=(4.4 * max(len(done), 1), 4.2), squeeze=False)\n",
|
||||
"for ax, (filters, label) in zip(axes[0], done):\n",
|
||||
" for name in (f'{MONO}, flattened', f'{POLY}, flattened'):\n",
|
||||
" if name not in results[filters]:\n",
|
||||
" continue\n",
|
||||
" r = results[filters][name]\n",
|
||||
" centre = r['fit']['beta'][1]\n",
|
||||
" ax.errorbar(r['x'] - centre, r['z'], yerr=r['z_err'], fmt='.', ms=3, lw=.6,\n",
|
||||
" color=colours[name], label=f\"{name}: $\\\\sigma$ = {r['sigma']:.3f} $\\\\pm$ {r['sigma_err']:.3f} um\")\n",
|
||||
" grid = np.linspace(-N_SIGMA * r['sigma'], N_SIGMA * r['sigma'], 300)\n",
|
||||
" ax.plot(grid, r['fit']['model'](grid + centre), color=colours[name], lw=1.2)\n",
|
||||
" ax.set_xlim(-8, 8); ax.set_ylim(-0.1, 1.4)\n",
|
||||
" ax.set_title(f'{label} ({occupancy[filters]*100:.2f} %)', fontsize=10)\n",
|
||||
" ax.set_xlabel('distance from the fitted edge [um]'); ax.set_ylabel('knife / flat')\n",
|
||||
" ax.grid(alpha=.3); ax.legend(fontsize=7, loc='upper left')\n",
|
||||
"fig.suptitle(f'presampled ESF ({BIN_WIDTH_UM} um bins) and ODR fit within $\\\\pm${N_SIGMA:g} sigma')\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "5d493d1f",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:46.450231Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:46.450132Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:46.793813Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:46.793491Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1430x506 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"fig, axes = plt.subplots(1, 2, figsize=(13, 4.6))\n",
|
||||
"order = [f'{POLY}, flattened', f'{MONO}, flattened', 'eta', 'cluster CNN <=1ph', 'cluster CNN <=3ph']\n",
|
||||
"for name in order:\n",
|
||||
" points = [(occupancy[f] * 100, results[f][name]) for f, _ in FLUX if name in results[f]]\n",
|
||||
" if not points:\n",
|
||||
" continue\n",
|
||||
" occ = np.array([p[0] for p in points])\n",
|
||||
" style = dict(color=colours[name], marker='o', ls='-' if 'GridBased' in name else ':', lw=1.2, ms=5)\n",
|
||||
" axes[0].errorbar(occ, [p[1]['sigma'] for p in points], yerr=[p[1]['sigma_err'] for p in points],\n",
|
||||
" label=name, capsize=2, **style)\n",
|
||||
" axes[1].plot(occ, [p[1]['mtf50'] for p in points], label=name, **style)\n",
|
||||
"for ax, ylabel in zip(axes, ('LSF sigma [um]', 'MTF50 of the fitted Gaussian [lp/mm]')):\n",
|
||||
" ax.set_xscale('log'); ax.set_xlabel('occupancy, flat field in the ESF ROI [%]')\n",
|
||||
" ax.set_ylabel(ylabel); ax.grid(alpha=.3, which='both')\n",
|
||||
"axes[0].legend(fontsize=8)\n",
|
||||
"fig.suptitle('edge width against flux')\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "ea39bb23",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:46.795017Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:46.794926Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:47.276187Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:47.275894Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1936x429 with 4 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"frequency = np.linspace(0, 400, 800)\n",
|
||||
"fig, axes = plt.subplots(1, max(len(done), 1), figsize=(4.4 * max(len(done), 1), 3.9), squeeze=False)\n",
|
||||
"for ax, (filters, label) in zip(axes[0], done):\n",
|
||||
" for name in (f'{MONO}, flattened', f'{POLY}, flattened'):\n",
|
||||
" if name in results[filters]:\n",
|
||||
" sigma_mm = results[filters][name]['sigma'] / 1000\n",
|
||||
" ax.plot(frequency, np.exp(-2 * np.pi**2 * sigma_mm**2 * frequency**2), color=colours[name],\n",
|
||||
" label=f\"{name}: {results[filters][name]['mtf50']:.0f} lp/mm\")\n",
|
||||
" ax.axvline(200, color='k', ls=':', lw=.8)\n",
|
||||
" ax.axhline(0.5, color='grey', lw=.5)\n",
|
||||
" ax.set_title(f'{label} ({occupancy[filters]*100:.2f} %)', fontsize=10)\n",
|
||||
" ax.set_xlabel('spatial frequency [lp/mm]'); ax.set_ylabel('MTF (Gaussian from the fit)')\n",
|
||||
" ax.set_ylim(0, 1.02); ax.grid(alpha=.3); ax.legend(fontsize=7)\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "5d9c96d1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Relative DQE at 200 lp/mm\n",
|
||||
"\n",
|
||||
"Both models see the same beam at each flux point, so the ratio of the photons\n",
|
||||
"they detect is the ratio of their quantum efficiencies, and DQE ∝ QE · MTF² is\n",
|
||||
"comparable without the absolute flux. MTF(200) here is the one measured from the\n",
|
||||
"LSF."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "e261c1be",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:47.277410Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:47.277320Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:47.380917Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:47.380567Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"flux point occupancy photons 2-20 / 12 keV MTF(200) 12 keV MTF(200) 2-20 DQE(200) 2-20 / 12 keV\n",
|
||||
"3 filters 0.75% 1.0266 0.252 0.227 0.837\n",
|
||||
"2 filters 1.81% 1.0242 0.259 0.254 0.982\n",
|
||||
"1 filter 4.45% 1.0279 0.251 0.227 0.846\n",
|
||||
"0 filters 10.77% 1.0311 0.222 0.173 0.625\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(f\"{'flux point':10s} {'occupancy':>9s} {'photons 2-20 / 12 keV':>22s} {'MTF(200) 12 keV':>15s} \"\n",
|
||||
" f\"{'MTF(200) 2-20':>13s} {'DQE(200) 2-20 / 12 keV':>23s}\")\n",
|
||||
"relative_dqe = {}\n",
|
||||
"for filters, label in FLUX:\n",
|
||||
" r = results[filters]\n",
|
||||
" a, b = r.get(f'{POLY}, flattened'), r.get(f'{MONO}, flattened')\n",
|
||||
" if a is None or b is None:\n",
|
||||
" continue\n",
|
||||
" qe = a['photons'] / b['photons']\n",
|
||||
" relative_dqe[filters] = qe * (a['mtf200_lsf'] / b['mtf200_lsf'])**2\n",
|
||||
" print(f\"{label:10s} {occupancy[filters]*100:8.2f}% {qe:22.4f} {b['mtf200_lsf']:15.3f} \"\n",
|
||||
" f\"{a['mtf200_lsf']:13.3f} {relative_dqe[filters]:23.3f}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9de8f3c7",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3. What the energy head reports at 12 keV\n",
|
||||
"\n",
|
||||
"The polychromatic model also measures every photon's energy. On a\n",
|
||||
"monochromatic beam the spectrum shows where it puts the 12 keV line, how wide it\n",
|
||||
"is, and how much ends up off the line: charge lost at the halo / edges below, and\n",
|
||||
"pile-up (two photons in one cell) above — the model cannot report more than one\n",
|
||||
"photon per cell or much beyond its 20 keV range."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "70897b20",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:47.382133Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:47.382048Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:48.050311Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:48.050022Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"run line [keV] core sigma [keV] < 10.5 keV 10.5-13.5 > 13.5 keV\n",
|
||||
"Edge_3filters_pos0 12.045 0.408 4.32% 94.84% 0.84%\n",
|
||||
"Flat_3filters_pos0 12.055 0.407 4.01% 95.15% 0.84%\n",
|
||||
"Edge_2filters 12.010 0.422 4.91% 93.08% 2.01%\n",
|
||||
"Flat_2filters 12.006 0.422 4.85% 93.11% 2.04%\n",
|
||||
"Edge_1filters 11.910 0.458 7.44% 87.38% 5.19%\n",
|
||||
"Flat_1filters 11.891 0.459 7.44% 87.34% 5.21%\n",
|
||||
"Edge_0filters 11.642 0.572 13.41% 72.68% 13.90%\n",
|
||||
"Flat_0filters 11.637 0.574 13.48% 72.46% 14.05%\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1430x484 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def gauss(x, a, mu, sig):\n",
|
||||
" return a * np.exp(-0.5 * ((x - mu) / sig)**2)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def line_fit(centres, counts, guess=12.0, half_window=0.8):\n",
|
||||
" # Gaussian core of the line; weighted mean / rms of the window if the fit fails\n",
|
||||
" near = np.abs(centres - guess) < 2\n",
|
||||
" peak = centres[near][np.argmax(counts[near])]\n",
|
||||
" window = np.abs(centres - peak) < half_window\n",
|
||||
" x, y = centres[window], counts[window]\n",
|
||||
" try:\n",
|
||||
" pars, _ = curve_fit(gauss, x, y, p0=(y.max(), peak, 0.3), maxfev=20000)\n",
|
||||
" return pars[1], abs(pars[2])\n",
|
||||
" except Exception:\n",
|
||||
" mean = np.average(x, weights=y)\n",
|
||||
" return mean, np.sqrt(np.average((x - mean)**2, weights=y))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"fig, axes = plt.subplots(1, 2, figsize=(13, 4.4))\n",
|
||||
"print(f\"{'run':30s} {'line [keV]':>11s} {'core sigma [keV]':>16s} {'< 10.5 keV':>10s} \"\n",
|
||||
" f\"{'10.5-13.5':>9s} {'> 13.5 keV':>10s}\")\n",
|
||||
"spectra = {}\n",
|
||||
"for filters, label in FLUX:\n",
|
||||
" for kind, ax in (('Edge', axes[0]), ('Flat', axes[1])):\n",
|
||||
" path = run_dir(f'{kind}_{filters}_12keV', POLY_TAG) / 'energy_spectrum.npy'\n",
|
||||
" if not path.exists():\n",
|
||||
" continue\n",
|
||||
" centres, counts = np.load(path)\n",
|
||||
" total = counts.sum()\n",
|
||||
" mu, sig = line_fit(centres, counts)\n",
|
||||
" low, mid, high = (counts[centres < 10.5].sum() / total, counts[(centres >= 10.5) & (centres <= 13.5)].sum() / total,\n",
|
||||
" counts[centres > 13.5].sum() / total)\n",
|
||||
" spectra[f'{kind}_{filters}'] = dict(line_keV=mu, core_sigma_keV=sig, below=low, line=mid, above=high)\n",
|
||||
" print(f\"{kind + '_' + filters:30s} {mu:11.3f} {sig:16.3f} {low*100:9.2f}% {mid*100:8.2f}% {high*100:9.2f}%\")\n",
|
||||
" ax.semilogy(centres, counts / total / np.diff(centres)[0], lw=1,\n",
|
||||
" label=f'{label} ({occupancy[filters]*100:.2f} %)')\n",
|
||||
"for ax, kind in zip(axes, ('knife edge', 'flat field')):\n",
|
||||
" ax.set_xlim(0, 30); ax.set_ylim(1e-6, 5)\n",
|
||||
" ax.set_xlabel('reconstructed photon energy [keV]'); ax.set_ylabel('photons / keV (normalised)')\n",
|
||||
" ax.set_title(f'{kind}, {POLY}'); ax.grid(alpha=.3, which='both'); ax.legend(fontsize=8)\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "1c638bc8",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4. Fake photons on dark runs (1000 frames each, pedestal of another run)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "50b9539e",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:48.051536Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:48.051448Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:48.232125Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:48.231785Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"run model frames photons per frame\n",
|
||||
"Pedestal_1filters_12keV GridBased 2-20 keV 1000 106 0.1060\n",
|
||||
"Pedestal_1filters_12keV GridBased 12 keV 1000 0 0.0000\n",
|
||||
"Pedestal_2filters_12keV GridBased 2-20 keV 1000 105 0.1050\n",
|
||||
"Pedestal_3filters_pos0_12keV GridBased 2-20 keV 1000 73 0.0730\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(f\"{'run':30s} {'model':20s} {'frames':>7s} {'photons':>8s} {'per frame':>10s}\")\n",
|
||||
"dark = {}\n",
|
||||
"for run in ('Pedestal_1filters_12keV', 'Pedestal_2filters_12keV', 'Pedestal_3filters_pos0_12keV'):\n",
|
||||
" for model, tag in ((POLY, POLY_TAG), (MONO, ''), (MONO, 'darktest')):\n",
|
||||
" s = summary_of(run, tag)\n",
|
||||
" if s is None:\n",
|
||||
" continue\n",
|
||||
" dark[f'{run}_{tag}'] = s['n_photons']\n",
|
||||
" print(f\"{run:30s} {model:20s} {s['n_frames']:7d} {s['n_photons']:8d} {s['n_photons']/s['n_frames']:10.4f}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "eec26108",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 5. The model on Monte Carlo\n",
|
||||
"\n",
|
||||
"Fixed-occupancy evaluation of the new checkpoint (`scripts/04_evaluate.py`,\n",
|
||||
"threshold 0.3) and its energy response (`scripts/07_energy_response.py`,\n",
|
||||
"occupancy ≤ 2.5 %), both on MOENCH040 2–20 keV frames the network never saw."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"id": "4271e8af",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:48.233350Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:48.233268Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:48.349056Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:48.348722Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"occupancy efficiency purity RMS [um] sigma68 [um] E sigma68 [keV]\n",
|
||||
" 0.5% 99.54% 98.44% 1.171 0.775 0.348\n",
|
||||
" 1% 99.25% 98.02% 1.257 0.808 0.364\n",
|
||||
" 2% 98.62% 97.53% 1.400 0.858 0.391\n",
|
||||
" 5% 96.65% 95.85% 1.859 1.041 0.524\n",
|
||||
" 10% 93.61% 93.09% 2.650 1.461 0.925\n",
|
||||
"\n",
|
||||
"energy response (epoch 182):\n",
|
||||
"E_true [keV] line - E [meV] core sigma [keV] efficiency\n",
|
||||
" 2.375 70 0.202 95.58%\n",
|
||||
" 3.875 8 0.304 97.77%\n",
|
||||
" 5.875 -5 0.319 98.39%\n",
|
||||
" 7.875 -7 0.339 98.64%\n",
|
||||
" 9.875 1 0.381 99.41%\n",
|
||||
" 11.875 -5 0.391 99.52%\n",
|
||||
" 14.875 -13 0.388 99.77%\n",
|
||||
" 17.875 -4 0.386 99.64%\n",
|
||||
" 19.375 -85 0.317 99.77%\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"eval_path = POLY_EXPERIMENT / 'eval_summary.json'\n",
|
||||
"if eval_path.exists():\n",
|
||||
" ev = json.load(open(eval_path))\n",
|
||||
" print(f\"{'occupancy':>9s} {'efficiency':>10s} {'purity':>8s} {'RMS [um]':>9s} {'sigma68 [um]':>12s} {'E sigma68 [keV]':>15s}\")\n",
|
||||
" for key, value in ev.items():\n",
|
||||
" m = value['summary']\n",
|
||||
" print(f\"{key:>9s} {m['efficiency']*100:9.2f}% {m['purity']*100:7.2f}% {m['rms_1d_um']:9.3f} \"\n",
|
||||
" f\"{m['sigma68_1d_um']:12.3f} {m['energy_sigma68_keV']:15.3f}\")\n",
|
||||
"else:\n",
|
||||
" print('no eval_summary.json in', POLY_EXPERIMENT)\n",
|
||||
"response_path = POLY_EXPERIMENT / 'energy_response.npz'\n",
|
||||
"if response_path.exists():\n",
|
||||
" r = np.load(response_path)\n",
|
||||
" print(f\"\\nenergy response (epoch {int(r['epoch'])}):\")\n",
|
||||
" print(f\"{'E_true [keV]':>12s} {'line - E [meV]':>14s} {'core sigma [keV]':>16s} {'efficiency':>10s}\")\n",
|
||||
" for energy in (2.5, 4.0, 6.0, 8.0, 10.0, 12.0, 15.0, 18.0, 19.5):\n",
|
||||
" i = int(np.argmin(np.abs(r['table_centre'] - energy)))\n",
|
||||
" print(f\"{r['table_centre'][i]:12.3f} {(r['table_core_mu'][i]-r['table_centre'][i])*1000:14.0f} \"\n",
|
||||
" f\"{r['table_core_sigma'][i]:16.3f} {r['table_efficiency'][i]*100:9.2f}%\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "0c49b3fa",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 6. Summary"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"id": "89072280",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T08:22:48.350375Z",
|
||||
"iopub.status.busy": "2026-09-28T08:22:48.350271Z",
|
||||
"iopub.status.idle": "2026-09-28T08:22:48.475704Z",
|
||||
"shell.execute_reply": "2026-09-28T08:22:48.475399Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"flux point occupancy sigma, 12 keV model [um] sigma, 2-20 keV model [um] MTF50 12 keV / 2-20 keV\n",
|
||||
"3 filters 0.75% 1.360 +- 0.019 1.420 +- 0.021 138 / 132 lp/mm\n",
|
||||
"2 filters 1.81% 1.346 +- 0.019 1.391 +- 0.018 139 / 135 lp/mm\n",
|
||||
"1 filter 4.45% 1.388 +- 0.020 1.551 +- 0.028 135 / 121 lp/mm\n",
|
||||
"0 filters 10.77% 1.473 +- 0.017 1.856 +- 0.037 127 / 101 lp/mm\n",
|
||||
"\n",
|
||||
"written to /home/xie_x1/MLXID/GridBased/Results/overnight_poly2to20keV_Moench040/report/knife_edge_poly2to20keV_summary.json\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"summary = dict(\n",
|
||||
" poly_experiment=POLY_EXPERIMENT.name, poly_tag=POLY_TAG, mono_experiment=MONO_EXPERIMENT.name,\n",
|
||||
" roi_superpixel=list(ROI), bin_um=BIN_UM, esf_bin_width_um=BIN_WIDTH_UM, odr_window_sigma=N_SIGMA,\n",
|
||||
" convention='sigma = ODR p2 (Gaussian LSF); MTF50 = 1000 sqrt(ln 2 / 2) / (pi sigma)',\n",
|
||||
" occupancy_flat_esf_roi=occupancy,\n",
|
||||
" occupancy_flat_esf_roi_poly={f: flat_occupancy(f, POLY_TAG) for f, _ in FLUX},\n",
|
||||
" results={f: {name: {k: float(r[k]) for k in ('sigma', 'sigma_err', 'chi2_ndf', 'mtf50',\n",
|
||||
" 'mtf50_lsf', 'mtf200_lsf', 'photons', 'rows_kept')}\n",
|
||||
" for name, r in results[f].items()} for f, _ in FLUX},\n",
|
||||
" relative_dqe_200lpmm=relative_dqe, spectra=spectra, dark_photons=dark, missing=missing)\n",
|
||||
"out = OVERNIGHT / 'report' / 'knife_edge_poly2to20keV_summary.json'\n",
|
||||
"out.parent.mkdir(parents=True, exist_ok=True)\n",
|
||||
"json.dump(summary, open(out, 'w'), indent=1)\n",
|
||||
"\n",
|
||||
"print(f\"{'flux point':10s} {'occupancy':>9s} {'sigma, 12 keV model [um]':>24s} {'sigma, 2-20 keV model [um]':>26s} \"\n",
|
||||
" f\"{'MTF50 12 keV / 2-20 keV':>24s}\")\n",
|
||||
"for filters, label in FLUX:\n",
|
||||
" a, b = results[filters].get(f'{POLY}, flattened'), results[filters].get(f'{MONO}, flattened')\n",
|
||||
" if a is None or b is None:\n",
|
||||
" continue\n",
|
||||
" print(f\"{label:10s} {occupancy[filters]*100:8.2f}% {b['sigma']:15.3f} +- {b['sigma_err']:.3f} \"\n",
|
||||
" f\"{a['sigma']:17.3f} +- {a['sigma_err']:.3f} {b['mtf50']:12.0f} / {a['mtf50']:.0f} lp/mm\")\n",
|
||||
"print(f'\\nwritten to {out}')"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "pytorch_nightly",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.18"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,661 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "86bf6c9c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Siemens star, 15 keV, MOENCH040 — polychromatic 2–20 keV GridBased model\n",
|
||||
"\n",
|
||||
"SOLEIL 2504 beamtime, MOENCH040 @150 V, 15 keV, 20 M frames of the full chip\n",
|
||||
"(2000 files). The two regions of `DataProcess/Configs.py` are reconstructed:\n",
|
||||
"\n",
|
||||
"| region | x [px] | y [px] |\n",
|
||||
"|---|---|---|\n",
|
||||
"| `SiemenStarLowerLeft` | 130–240 | 110–220 |\n",
|
||||
"| `SiemenStarLowerRight` | 235–345 (the notebooks use 234–344) | 110–220 |\n",
|
||||
"\n",
|
||||
"Both share the same rows, so one crop of the frame, x 126–349 and y 106–224\n",
|
||||
"(the regions plus the network's halo R = 4), is read and reconstructed in one\n",
|
||||
"pass; its valid region is x 130–345, y 110–220. Reconstruction: the 2–20 keV\n",
|
||||
"MOENCH040 model, FP16 with an FP32 head, masked column common mode (median over the pixels without charge) over the\n",
|
||||
"118 rows of the crop, self-flattening of the sub-pixel phase with one Rosenblatt table per\n",
|
||||
"local-occupancy class (tables from the first 3·10⁸ photons, every photon\n",
|
||||
"remapped; one table for the whole crop left a 25 µm grid in the dim star of\n",
|
||||
"LowerLeft, whose occupancy is ~8x below the rest). The run is processed as four parts of 500\n",
|
||||
"files; this notebook sums the parts it finds.\n",
|
||||
"\n",
|
||||
"For comparison, the published cluster-based reconstructions of the same regions\n",
|
||||
"(`SiementStar_LowerLeft/Right.ipynb`): eta interpolation (single-photon clusters)\n",
|
||||
"and the 1/2/3-photon CNNs summed (`≤3ph`), all at 2.5 µm."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "5e4befe5",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T10:33:40.244153Z",
|
||||
"iopub.status.busy": "2026-09-28T10:33:40.244075Z",
|
||||
"iopub.status.idle": "2026-09-28T10:33:40.777351Z",
|
||||
"shell.execute_reply": "2026-09-28T10:33:40.777052Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"parts found: 4 of 4 ['SiemensStar_15keV_part0', 'SiemensStar_15keV_part1', 'SiemensStar_15keV_part2', 'SiemensStar_15keV_part3']\n",
|
||||
"model 260927_poly2to20keV_Moench040_c96_00 (epoch 182), 20,000,000 frames, 1.6259e+10 photons (813.0 per frame in the 23650 px valid region)\n",
|
||||
" SiemensStar_15keV_part0 files [0, 499, 1] 5,000,000 frames occupancy 3.29 % (illuminated 5.58 %) 2434 frame/s sub-pixel rms 17.2 -> 1.2 %\n",
|
||||
" SiemensStar_15keV_part1 files [500, 999, 1] 5,000,000 frames occupancy 3.45 % (illuminated 5.88 %) 1970 frame/s sub-pixel rms 17.3 -> 1.1 %\n",
|
||||
" SiemensStar_15keV_part2 files [1000, 1499, 1] 5,000,000 frames occupancy 3.50 % (illuminated 5.96 %) 2325 frame/s sub-pixel rms 17.3 -> 1.1 %\n",
|
||||
" SiemensStar_15keV_part3 files [1500, 1999, 1] 5,000,000 frames occupancy 3.51 % (illuminated 5.97 %) 2391 frame/s sub-pixel rms 17.3 -> 1.1 %\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import json\n",
|
||||
"import os\n",
|
||||
"from pathlib import Path\n",
|
||||
"\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import numpy as np\n",
|
||||
"from scipy.optimize import curve_fit\n",
|
||||
"\n",
|
||||
"GRID = Path('/mnt/sls_det_storage/moench_data/MLXID/InferenceResults/GridBased')\n",
|
||||
"PUBLISHED = Path('/home/xie_x1/MLXID/DeepLearning/InferenceResults')\n",
|
||||
"ETA = Path('/home/xie_x1/MLXID/EtaInterpolation/Results')\n",
|
||||
"OVERNIGHT = Path('/home/xie_x1/MLXID/GridBased/Results/overnight_poly2to20keV_Moench040')\n",
|
||||
"POLY_TAG = os.environ.get('GRID_POLY_TAG', 'poly2to20')\n",
|
||||
"RUNS = [r.strip() for r in os.environ.get(\n",
|
||||
" 'GRID_STAR_RUNS', ','.join(f'SiemensStar_15keV_part{i}' for i in range(4))).split(',')]\n",
|
||||
"CNN = {1: '1ph_260616_15keV_v260511_00', 2: '2ph_260622_15keV_v260610_00',\n",
|
||||
" 3: '3ph_260623_15keV_v260611_00'}\n",
|
||||
"B = 10 # 2.5 um bins per 25 um pixel\n",
|
||||
"# region -> (x0, x1, y0, y1) in chip pixels: the whole region, the zoom of the\n",
|
||||
"# published notebooks, and the 50 x 50 px FRC box (SiementStar_LowerLeft.ipynb's\n",
|
||||
"# [1200:2100, 1400:2300][200:-200, 220:-180]; the same box around the right star)\n",
|
||||
"REGIONS = {'LowerLeft': dict(roi=(130, 240, 110, 220), zoom=(140, 190, 170, 210), frc=(162, 212, 140, 190)),\n",
|
||||
" 'LowerRight': dict(roi=(234, 344, 110, 220), zoom=(284, 324, 160, 200), frc=(263, 313, 140, 190))}\n",
|
||||
"\n",
|
||||
"plt.rcParams.update({'figure.dpi': 110, 'image.origin': 'lower', 'image.interpolation': 'nearest'})\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def run_dir(run):\n",
|
||||
" return GRID / (run + (f'_{POLY_TAG}' if POLY_TAG else ''))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"parts = [r for r in RUNS if (run_dir(r) / 'binned_image_flattened.npy').exists()]\n",
|
||||
"print(f'parts found: {len(parts)} of {len(RUNS)} {parts}')\n",
|
||||
"summaries = [json.load(open(run_dir(r) / 'summary.json')) for r in parts]\n",
|
||||
"frames = np.array([s['n_frames'] for s in summaries], float)\n",
|
||||
"flattened = sum(np.load(run_dir(r) / 'binned_image_flattened.npy').astype(float) for r in parts)\n",
|
||||
"raw = sum(np.load(run_dir(r) / 'binned_image.npy').astype(float) for r in parts)\n",
|
||||
"analog = sum(np.load(run_dir(r) / 'analog_image.npy') * n for r, n in zip(parts, frames)) / frames.sum()\n",
|
||||
"spectrum_centres = np.load(run_dir(parts[0]) / 'energy_spectrum.npy')[0]\n",
|
||||
"spectrum = sum(np.load(run_dir(r) / 'energy_spectrum.npy')[1] for r in parts)\n",
|
||||
"crop_x0, _, crop_y0, _ = summaries[0]['crop']\n",
|
||||
"print(f\"model {Path(summaries[0]['checkpoint']).parent.parent.name} (epoch {summaries[0]['epoch']}), \"\n",
|
||||
" f\"{frames.sum():,.0f} frames, {sum(s['n_photons'] for s in summaries):.4e} photons \"\n",
|
||||
" f\"({sum(s['n_photons'] for s in summaries)/frames.sum():.1f} per frame in the \"\n",
|
||||
" f\"{summaries[0]['valid_pixels']} px valid region)\")\n",
|
||||
"for s in summaries:\n",
|
||||
" print(f\" {s['run']:28s} files {s['signal_files']} {s['n_frames']:>10,d} frames \"\n",
|
||||
" f\"occupancy {s['occupancy_valid_region']*100:.2f} % (illuminated {s['occupancy_exposed']*100:.2f} %) \"\n",
|
||||
" f\"{s['frames_per_second']:.0f} frame/s sub-pixel rms {s['subpixel_nonuniformity_before']*100:.1f} -> \"\n",
|
||||
" f\"{s['subpixel_nonuniformity_after']*100:.1f} %\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "54a0702c",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T10:33:40.778887Z",
|
||||
"iopub.status.busy": "2026-09-28T10:33:40.778584Z",
|
||||
"iopub.status.idle": "2026-09-28T10:33:40.970833Z",
|
||||
"shell.execute_reply": "2026-09-28T10:33:40.970515Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def cut_grid(image, box, factor=B):\n",
|
||||
" # chip-pixel box -> the GridBased crop's binned image\n",
|
||||
" x0, x1, y0, y1 = box\n",
|
||||
" return image[(y0 - crop_y0) * factor:(y1 - crop_y0) * factor,\n",
|
||||
" (x0 - crop_x0) * factor:(x1 - crop_x0) * factor]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def cut_chip(image, box, factor=B):\n",
|
||||
" # chip-pixel box -> a full-chip super-frame (4000 x 4000 at 2.5 um)\n",
|
||||
" x0, x1, y0, y1 = box\n",
|
||||
" return image[y0 * factor:y1 * factor, x0 * factor:x1 * factor]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def published(region):\n",
|
||||
" eta = np.load(ETA / f'SiemenStar{region}_fromClusters.npy', mmap_mode='r')\n",
|
||||
" single = cnn = None\n",
|
||||
" for n, experiment in CNN.items():\n",
|
||||
" path = (PUBLISHED / f'SiemenStar{region}' / experiment / 'augX1'\n",
|
||||
" / f'{n}Photon_ML_superFrame_etaInterpolated.npy')\n",
|
||||
" if path.exists():\n",
|
||||
" image = np.asarray(np.load(path, mmap_mode='r'), float)\n",
|
||||
" single = image if n == 1 else single\n",
|
||||
" cnn = image if cnn is None else cnn + image\n",
|
||||
" return eta, single, cnn\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"images = {}\n",
|
||||
"for region, boxes in REGIONS.items():\n",
|
||||
" eta, single, cnn = published(region)\n",
|
||||
" images[region] = {}\n",
|
||||
" for key, box in boxes.items():\n",
|
||||
" images[region][key] = {\n",
|
||||
" 'native readout (25 um)': cut_grid(analog, box, factor=1),\n",
|
||||
" 'eta interpolation': np.asarray(cut_chip(eta, box), float),\n",
|
||||
" 'cluster CNN 1ph': cut_chip(single, box) if single is not None else None,\n",
|
||||
" 'cluster CNN <=3ph': cut_chip(cnn, box) if cnn is not None else None,\n",
|
||||
" 'GridBased 2-20 keV': cut_grid(flattened, box),\n",
|
||||
" }\n",
|
||||
" images[region]['roi_raw_grid'] = cut_grid(raw, boxes['roi'])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "43f9cd97",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1. The two regions"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "29d6aaff",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T10:33:40.972383Z",
|
||||
"iopub.status.busy": "2026-09-28T10:33:40.972301Z",
|
||||
"iopub.status.idle": "2026-09-28T10:33:41.986287Z",
|
||||
"shell.execute_reply": "2026-09-28T10:33:41.985991Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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C+U2T548WS7T3usBAD788EOcfPLJ0Ov1SEtLw1VXXYWamhooFIpm1SFbeg8AXn31VZx88skwmUwwGo3o378/Xn/99WbL0fVXXl6Oyy67DA6HA3q9HgMHDsS3337brv1vDbPZLIV1B4MQAvX19S0em0NBCIF77rkHCoUCN998M2KxGID2PXMVCgWuuOIKNDQ04M0332zx91944QUYDAZcfPHFh2V7GYZhGIZhGIZhGIZhCK5cxzAMwzAMwzAMwzDMYaVjx44AgEWLFuHhhx8+pMpfJSUlGDBgABoaGnDFFVegS5cu2L9/P/7zn//g448/xjfffIO8vLyE79x1110IBoP45z//CZVKhQULFmDMmDF46623cMUVV+CCCy7AqFGjsHHjRrz00ktISUnBwoULf9M67777btTX12PSpEkwmUx4+eWXceuttyIzMxMXXnghgCax4bBhw+ByuTB58mRkZmaiqqoK3333HTZu3IhRo0a1eSwuuOACrF27FldffTV69+6NYDCIXbt2Yc2aNQAAl8uFxYsX45ZbboHT6cQ999wjv+tyuQAAy5Ytw5YtWzBu3Djk5+fD4/HgzTffxMSJE1FVVYXbb7+92XovueQSaDQaXH/99TAajejatetBnMGWiUajGDFiBNauXYuRI0fi+uuvR3l5Of7zn//g1FNPxQcffIDBgwcDaKpWtXr1avzwww+yzeOaNWugVCrR0NCAL7/8Eqeddpp8H0gUdL7wwgu48sor0bt3b9x5552wWq3YsGED7rrrLnz//ffNRE4NDQ047bTTcNJJJ2HmzJnwer0tVshqjUgkghEjRmD9+vW46KKLcO2118Ln8+GVV17BkCFDsHz5cowcORKnn346Fi9ejAceeABut1uKMXNzc1FSUoLLLrsMp512Gq6++upDPs5arRannXYa1q5di1gsBqVSmXD8Pv/8cwSDQaSkpMj3LRYL+vbtm/A7CxcuxP79+3HllVfC5XLhnXfewezZs2E2m3HnnXfK5T788EOMHj0aFosFkydPRnp6OlatWoVp06bhiy++wMqVK+U2/JZj1x4WLFiAiooKXH311cjOzobZbAZwcNfDe++9h3PPPReZmZm48847YbPZ8O677+Kss85q3wkAMG3aNNx///3o1asX7r33XgDAK6+8gosuugi7d+/G3XffnbB8Y2MjTjvtNPTt2xf3338/Kioq8Nhjj+Gss87C7t275X78XlitVtTX10OtVmPAgAGYNm1aq4LpAxEKhXDFFVfgtddew6OPPopbbrkFwME9cydNmoQZM2bg+eefx+WXX57w+//973/x888/Y8KECbBYLL9txxmGYRiGYRiGYRiGYZIRDMMwDMMwDMMwDMMwh5GioiJhtVoFAJGeni4uuOAC8cgjj4gvv/xSxGKxZstPmDBBJLsoxo4dK2w2m9i1a1fC+7t37xYmk0lMnDhRvrdo0SIBQPTq1UsEAgH5/vfffy8ACIVCId54442E3xkzZozQaDTC6/Ue1nU2NDQIh8Mh/v73v8v3FixYIACIL7/8ss3j1hJ1dXVCoVCIa6+99oDL5ufni4EDB7b4WUNDQ7P3otGoOP3004XVahWhUEi+P336dAFAnH766SIcDrd7W/Pz80XHjh3bXOb5558XAMQ///nPhPd/+eUXkZKSIjp37iyi0agQQohNmzYJAGLOnDlyuYEDB4qRI0cKm80mpk2bJt8/55xzhM1mk98tKysTOp1OjB07ttk1N3fuXAFArFu3LuF3AYi77767xe0GIIYOHdrmvs2fP18AEO+8807C+6FQSPTu3VsUFhYmvD9w4ECRn5/f4romTJjQ5rraA+3n119/LYQQwu/3C51OJy677DIBQHz66adCCCEikYiwWCxizJgx8rtr164VAERGRoaoqamR70ejUdGtWzeRmZkp34tEIqKgoEAYDAaxe/fuhG2YNGmSACAWL14s36N7Z+3atfK9gz12LUHbbLPZREVFRcJnB3M9RCIRkZeXJ1JTU0VpaWnCvo8ZM6bF85P83vbt24VSqRR9+vQRPp9Pvt/Q0CCOP/54oVKpRFFRkXyfrr/Zs2cn/O6SJUsEALFw4cID7n97OdC1fMcdd4gbb7xRLF68WCxfvlzMmjVLOJ1OoVAoxKuvvtquddAzpKioSNTV1YnBgwcLnU4nli5dmrDcwTxzhRBi5MiRAoDYunVrwvsTJ04UAMTnn3/eru1jGIZhGIZhGIZhGIY5GLgtLMMwDMMwDMMwDMMwh5WCggL873//w4033giDwYA333wTt912G/r3748uXbrIKmOt4fF48N5772HEiBFITU2F2+2Wf2azGf3798dHH33U7HvXX3+9rMQFACeeeCJSU1ORmZmJCy64IGHZgQMHIhwOy9aDh2udRqMRf//732VrXKCpAhQALF++HH6//4DHLx69Xo+UlBR89dVX2L1790F9Nx6j0Sj/7/f7UV1djZqaGpx55pmoq6vDL7/80uw7t9xyyyFVHWyLt99+G0BTVa94unTpgosvvhg7duzAjz/+CADo06cPbDabvF58Ph82btyIM844A4MGDZLvRyILine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 2530x506 with 5 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAACc8AAAIPCAYAAACvu7RHAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AAEAAElEQVR4nOydd5hT1fb3v+l10iaZzhQGGECKVBGlgwVBULEXsF97uWKXol7FdkW92AtiAQtiAawIiAqiCNLr9J4pSSYz6TnvH7xr/5LMwAwIYlmf55kHcnJyzj51r73Wd60tkyRJAsMwDMMwDMMwDMMwDMMwDMMwDMMwDMMwDMMwDMP8g5Af6wYwDMMwDMMwDMMwDMMwDMMwDMMwDMMwDMMwDMMwzB8Ni+cYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmGYfxwsnmMYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmH+cbB4jmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhvnHweI5hmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEY5h8Hi+cYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmGYfxwsnmMYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmH+cbB4jmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhvnHweI5hmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEY5h8Hi+cYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmGYfxwsnmMYhmEYhmEYhmEY5qgxbdo0yGSyY90MhjlizJ8/HzKZDKtWrTrsbYwcORK5ublHrE1/BEfiuA/ErFmzIJPJUFxcfMS3fSwoLi6GTCbDrFmzjnVT/jRwX8AwDMMwDMMwDMMwzJ8VFs8xDMMwDMMwDMMwDHNI1NbW4u6770bv3r1hMpmQlJSEzp0746yzzsJrr712rJv3t2Tu3LmYP3/+Mdt/bm4uunTpcsz2fzSRyWRxfxqNBnl5ebj66qtRXl5+rJsHl8uFWbNmHRXRGvPPZNeuXZg+fTrGjh2L5ORkyGQyXHXVVQdcf+TIka2eE/pbunTpH9jy/2Pw4MFQKpXtPqP9+/eHWq1GbW3tH9QyhmEYhmEYhmEYhmH+aiiPdQMYhmEYhmEYhmEYhvnrUFpaisGDB6Ourg5TpkzB1VdfDbVajcLCQnz99deYO3currzySrH+K6+8ghdffPEYtvjvwdy5c5Gbm4tp06Yd66b8LTnuuONw9913AwA8Hg++++47vPbaa1i+fDk2b96M5ORkse6ll16KCy64AGq1+g9pm8vlwuzZswHsFzExf35ycnLg8/mgVP45Xa9r167Fk08+iby8PAwaNAhffvllu7+x2+14+umnWy3v16/f0Whiu1x99dW45pprMH/+fNx///1trrNx40Zs3LgRZ599NlJSUv7gFjIMwzAMwzAMwzAM81fhz+nBYRiGYRiGYRiGYRjmT8mTTz6JmpoazJ07F7fcckur7xOrAKlUKqhUqj+qecxhEI1GEQgEoNPpjnVT/jACgQAUCoUQN6WlpeGSSy4R319//fVIS0vDM888g/nz5+Pf//63+E6hUEChUPzhbWaODJIkwefzQa/XH7V9yGQyaLXao7b938vEiRPR0NAAq9WK4uJi5OXltfsbg8EQ94wcay688ELcfvvteP3113Hfffe1OSXsq6++CgAHrarHMAzDMAzDMAzDMAzD07YyDMMwDMMwDMMwDNNhdu/eDQAYM2ZMm99nZWXFfZ42bVqbooaamhrcdNNNyM3NhVqtRmpqKi655BIUFxfHrTd//nzIZDKsWLECjzzyCDp37gytVou+ffvi888/BwBs374dEyZMgNlshsViwbRp0+D1en/3PleuXIm5c+eiW7du0Gg06Ny5c5uVl9atW4eJEyciIyMDGo0G6enpGD16ND777LMDnkeisbER06dPR9euXaHT6WC1WtG7d28h1iouLoZMJkNJSQlWr14dN10itXv9+vW44oorUFBQAIPBAIPBgMGDB+PNN99stb9Zs2ZBJpNh+/btuPPOO5GTkwO1Wo333nuv3bZ2BL/fj9mzZ6N79+7QarWw2WyYOHEifvnll7j1xo0bB4fDAUmSxLIff/wRMpkMSUlJCIVCYvnmzZshk8nw+OOPx21j5cqVOP3002G1WqHRaNCjRw889thjiEQiceuNHDkSubm5KCkpwQUXXAC73Q6tVtvudI9jx44FAOzZsyduOd0fidOoVlVV4dJLL0VycjIMBgOGDRuG77777oDPAABUV1eL3+h0OowYMQIbNmyI2xcJm2bPni2ufW5u7kHb3hYVFRWQyWRxQkAAuOaaayCTyXDttdfGLb/99tshk8lQU1MTt1ySpA49FwDwxRdfYNSoUTCZTNDpdDj++OMxb968uOt+MJqamnDfffehoKAAGo0GNpsNkydPxubNmzv0e7pW33zzDR599FHR5th7afHixRgxYoRoY79+/YToKpG33noLffr0gUajQVZWFu68807s2LEDMpkMs2bNEuvRcxu7DNgvVH322WfRt29f6HQ6mEwmjB49Gl9//XWrfeXm5mLkyJHYvXs3Jk2aBLPZDKPRiDPOOAP79u3r0PEfiOTkZFit1kP+XTQahcfjQTQa/V37J0KhEKZNmwa5XI4nn3xSLN+3bx+mTZuGjIwMqNVqZGVl4frrr0ddXZ1Yx2g04vzzz0dRURFWrlzZatt+vx/vvvsusrOzceqppx6R9jIMwzAMwzAMwzAM8/eEK88xDMMwDMMwDMMwDNNh8vPzAQBvvPEGHnvsscOalrCsrAxDhw6F1+vFlVdeiW7duqGiogIvvPACvvrqK/zyyy/Izs6O+80999yDQCCA6667DgqFAs888wwmTZqEDz/8EFdeeSXOO+88TJw4EWvXrsWbb74JjUaDl1566Xft895774XH48Hll18Oo9GIBQsW4Pbbb0d6ejouuOACAPvFhGPHjoXD4cANN9yA9PR0OJ1O/Prrr1i7di0mTpx40HNx3nnnYeXKlbjmmmvQr18/BAIB7Nu3DytWrAAAOBwOvPXWW7jttttgt9tx3333id86HA4AwJIlS7B161ZMmTIFOTk5cLvdeP/99zFt2jQ4nU7ccccdrfZ78cUXQ6VS4cYbb4TBYEBBQcEhXMG2iUQiGD9+PFauXIkJEybgxhtvRHV1NV544QWcfPLJ+PzzzzFq1CgA+4Vp33zzDTZt2iSmfVyxYgXkcjm8Xi/WrVuHYcOGieVAvGDz9ddfx1VXXYV+/frh7rvvhsViwQ8//IB77rkHGzduxKJFi+La5vV6MWzYMAwePBizZ89GU1MTjEbjQY9n7969ABA3ZeuBcLvdGDZsGAoLC3HFFVdgwIAB2LFjB8aPH48uXbq0+Zvm5mYMGzYMAwYMwEMPPYSamho8/fTTOO2001BYWIikpCQMHz4cTz/9NG677TacddZZOPvsswGg3ba3RWZmJrp3745vvvkmbjmd97aW9+rVC6mpqXHLO/JcAMBrr72Gq6++Grm5uZg+fTqMRiM+/PBD3Hjjjfjtt9/w8ssvH7S9Ho8HJ598Mvbu3YupU6eib9++aGxsxCuvvIITTzwRa9asQf/+/Tt07NOnT4fP58PUqVPhcDjQqVMnAPvFpLNnz8aoUaMwc+ZM6HQ6fPnll7j66quxd+9ezJkzR2xj3rx5uPHGG9G9e3fMnj0bKpUKCxcubCWiPBjTpk3DW2+9hZNPPhmPPvoompqa8Oqrr+LUU0/FggULWlV2q6iowPDhw3HmmWfisccew549e/Dcc8/hzDPPxJYtWyCX/3F50RUVFTAajfD5fNBqtRg9ejQeeuihDl+DRDweD8455xysWbMGixYtwnnnnQcA2LRpE0aOHAm9Xo8rrrgCOTk52LNnD1544QWsWLEC69evh9lsBrB/6tbXXnsNr732GkaPHh23/Q8//BAulwu33HLLH3qeGIZhGIZhGIZhGIb5CyIxDMMwDMMwDMMwDMN0kKKiIslisUgApNTUVOm8886TnnrqKWndunVSNBpttf7UqVOlRPfD5MmTJavVKu3bty9ueWFhoWQ0GqVp06aJZW+88YYEQOrTp4/k9/vF8o0bN0oAJJlMJr333ntx25k0aZKkUqmkpqamI7pPr9crJScnSyeeeKJY9swzz0gApHXr1h30vLWFy+WSZDKZ9K9//avddXNycqQRI0a0+Z3X6221LBKJSMOHD5csFosUDAbF8pkzZ0oApOHDh0uhUKjDbc3JyZHy8/MPus5rr70mAZCuu+66uOW7du2SNBqN1LVrVykSiUiSJEk///yzBEB6/PHHxXojRoyQJkyYIFmtVmnGjBli+RlnnCFZrVbx26qqKkmr1UqTJ09udc898cQTEgBp1apVcdsFIN17771ttpvOh9PplJxOp1RYWCjNnz9fslgsklKplLZs2RK3Pt0fK1euFMvuvfdeCYA0b968uHUXL14sAWj1DFCbHnnkkbjlCxculABIL730klhWVFQkAZBmzpzZZvsPhRtuuEGSyWRSTU1N3LYvvfRSCYBUWFgoSZIk1dbWSjKZTLrllltaHXdHnguXyyUZjUYpMzNTqq+vF8tDoZA0btw4CYC0Zs0asZzuy6KiIrHs1ltvlVQqVatnq7GxUcrKypJGjhzZ7vFSm7t27drqOdm4caMkk8mkm2++uc3zJJfLxfuisbFRMhgMUufOnSWPxyPW8/v90qBBg1pdn7au2YoVKyQA0oQJE6RwOCyW19bWSikpKZLFYol7Z+Xk5EgApHfffTeubY8++qgEQPryyy/bPf6OQG298sorD7jO1KlTpXvuuUdauHChtHjxYumee+6RDAaDpNFo4p61gxHbF5SVlUm9e/eWrFar9N1338Wtd/zxx0t5eXlx940kSdK6deskuVwuzZo1K2557969Ja1WKzULine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 2530x506 with 5 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def limits(img):\n",
|
||||
" # grey levels from the central 60 % of the image: in LowerLeft the unshadowed\n",
|
||||
" # strip at x > 222 is several times brighter than the star (and brighter\n",
|
||||
" # still for GridBased, which does not lose its photons to pile-up)\n",
|
||||
" ny, nx = img.shape\n",
|
||||
" centre = img[int(.2 * ny):int(.8 * ny), int(.2 * nx):int(.8 * nx)]\n",
|
||||
" centre = centre[np.isfinite(centre)]\n",
|
||||
" return np.percentile(centre, 0.5), np.percentile(centre, 99.5)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def show(region, key, title):\n",
|
||||
" box = REGIONS[region][key]\n",
|
||||
" panels = [(name, img) for name, img in images[region][key].items() if img is not None]\n",
|
||||
" fig, axes = plt.subplots(1, len(panels), figsize=(4.6 * len(panels), 4.6))\n",
|
||||
" for ax, (name, img) in zip(axes, panels):\n",
|
||||
" low, high = limits(img)\n",
|
||||
" ax.imshow(img, cmap='gray', extent=[box[0], box[1], box[2], box[3]], vmin=low, vmax=high)\n",
|
||||
" ax.set_title(name, fontsize=10)\n",
|
||||
" ax.set_xlabel('x [pixel, 25 um]'); ax.set_ylabel('y [pixel, 25 um]')\n",
|
||||
" fig.suptitle(f'Siemens star {region}, {title}, 15 keV')\n",
|
||||
" fig.tight_layout()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"for region in REGIONS:\n",
|
||||
" show(region, 'roi', 'whole region')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "b4daba25",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T10:33:41.989993Z",
|
||||
"iopub.status.busy": "2026-09-28T10:33:41.989887Z",
|
||||
"iopub.status.idle": "2026-09-28T10:33:42.917327Z",
|
||||
"shell.execute_reply": "2026-09-28T10:33:42.917050Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAACdcAAAHtCAYAAADxptVPAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AAEAAElEQVR4nOzdd3RU1doG8Gf6TCbJlPReaAKCgoJcEAMIFgRBRUVRARV7RbFeBdRrL9i7CMrFgh0RRQRERcVesCA1hCSkJ5NMkpnM/v7ge/fNpAcpis9vLdYiM2fOnJk55+z27ncblFIKRERERERERERERERERERERERERKQZ9/UBEBEREREREREREREREREREREREf3VMLiOiIiIiIiIiIiIiIiIiIiIiIiIqAkG1xERERERERERERERERERERERERE1weA6IiIiIiIiIiIiIiIiIiIiIiIioiYYXEdERERERERERERERERERERERETUBIPriIiIiIiIiIiIiIiIiIiIiIiIiJpgcB0RERERERERERERERERERERERFREwyuIyIiIiIiIiIiIiIiIiIiIiIiImqCwXVERERERERERERERERERERERERETTC4joiIiIiIiIiIiIiIiIiIiIiIiKgJBtcRERERERERNTJlyhQYDIZ9fRhEe1UoFMKsWbOQnZ0Ns9nMa2APq6mpwWWXXYb09HSYTCZkZmbu8r6GDRv2p17/V2MwGDBlypQObbty5UoYDAY8//zz+rHNmzfDYDBg1qxZnX7vfXH//zPH+1f0V/o8nTmX9gctXQ9ERERERERE9OcxuI6IiIiIiIj2ezt27MB1112HPn36IDo6GlFRUcjOzsYJJ5yAZ599dl8f3n5pzpw5+3SAPzMzE127dt1n778nGQwGjBw5crfuc968eZg9ezaGDx+OZ599Fi+88AIAYNasWXjzzTd363sRcNddd+Hhhx/Gqaeeiueffx5z5sxpc/t9fT3R/m/lypWYNWsWysvL9/Wh7DfuvPNOnHrqqejWrRuMRiPMZnOr2z7//PMwGAwt/pswYcJePOr/eeyxx2AwGHDHHXe0ud1DDz0Eg8GABx54YC8dGREREREREdHe1XqLnoiIiIiIiGg/sHXrVgwcOBDFxcWYMGECpk2bBqvVio0bN2LZsmWYM2cOzjnnHL39008/jSeeeGIfHvH+Yc6c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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 2530x506 with 5 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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odPpMG7cOFgsFjRs2PAs3mD1eL1e9O7dG5s3b0bfvn0xbtw4pKWl4a233sL111+PdevWoWvXrgAqA9M2btyI3377DS1atAAAbNq0CWq1GkVFRdi5cyc6duwojwP+AZvvvfce7r77brRo0QJPPPEEQkJCsH37dvzvf//Dr7/+WiUopaioCB07dkSbNm0wffp0FBYWIigo6IzPc+jQIQDw27K1JvLz89GxY0ckJyfjzjvvRKtWrbB//3707t0b9erVq/Y3xcXF6NixI1q1aoVnnnkG6enpeOWVV3DTTTchOTkZVqsVnTp1wiuvvILx48dj4MCBGDRoEADUWvaaWLp0aZVje/fuxYwZMxARESGPffXVV+jfvz9sNhseeOABhIeHY+3atZgyZQq+//57rFmzBmp15brQkydPonXr1sjIyMCYMWPQrFkz/P7775g/fz6++uor/PjjjwgPD/e755tvvonMzEyMGTMGQUFBePfddzFy5EjodDr873//Q8eOHfHss8/izz//xBtvvIGRI0di/fr1tT7fb7/9hk6dOsHr9WLs2LFITEzEd999h9mzZ2Pjxo34/vvvYTabce+996JHjx64/fbb0bFjR9xzzz0AgPbt21d73UaNGmHp0qVVzj+dkydPolOnTujfvz9efPFFHDx4EK+99hr69++P3bt3yzrzeDzo3bs3tm7diqFDh+K+++5DSUkJ3n//fXTr1g0rV65E3759a31eAHj99ddx4sQJ3HfffXA4HFixYgWmTp2K5OTkGoMBA2X16tV4+eWXcf/99+Ouu+7Cxo0bMWfOHPzxxx/YsGGDfJ5Aef755/F///d/6NOnD+6++27o9XocO3YMX331FdLS0vzaSSD9gxg9ejSWLFmCAQMGYPjw4QCAzz//HAMHDsRbb72F++67T577xBNP4MUXX8S1116LF154AaWlpXjvvfewatWqs66fkSNHQqVS4aGHHoJarcabb76J4cOHIzExEe3atZPnTZkyBc888wyaNWuGp556CgDw/vvvY+jQoUhOTsbkyZMBVG7P/fLLL2Pbtm1+fZXaZUFBAa6//nocOnQII0eORPPmzZGbm4v58+fjuuuuw7Zt29CyZUu/MgbaPgLtO0BlwFeHDh2wb98+DB8+HO3bt8fhw4fx5ptv4quvvsL27dvPuMXp8uXLMWLECLRr1w4rVqxASEgIPB4PevbsiePHj2Ps2LG46qqrUFhYiL/++gvffPMNHn/88bN+P/+E5s2bo6CgAGq1Gi1atMCkSZNw6623ntO1hBD43//+hxdffBHjx4/H7NmzoVKpzup9Dh48GA899BAWLVqEadOm+fW9Y8eOYcOGDejcuTPq169/Xp6fYRiGYRiGYRiGYf4Line truncated
|
||||
"text/plain": [
|
||||
"<Figure size 2530x506 with 5 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"for region in REGIONS:\n",
|
||||
" show(region, 'zoom', 'zoom of the published notebooks')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cba943fe",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### GridBased 2–20 keV at full size\n",
|
||||
"\n",
|
||||
"The flattened reconstruction of each region at 2.5 µm, and the same photons\n",
|
||||
"before the sub-pixel flattening (the 25 µm pixel grid is visible there)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "76f70e13",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T10:33:42.920209Z",
|
||||
"iopub.status.busy": "2026-09-28T10:33:42.920105Z",
|
||||
"iopub.status.idle": "2026-09-28T10:33:43.673514Z",
|
||||
"shell.execute_reply": "2026-09-28T10:33:43.673248Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAABmYAAAMwCAYAAAA6Vd9WAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AAEAAElEQVR4nOz9eZzkdXXvj79q6aruquqq7qqu3nu6Z3p2hmUQBAURDBE30BijJsGAu17jEqMQQ77BGK8oUcyNSYg3XtGLRDHJ1XhdkhhFIEGv7OPADAOz9/TeXdVVvVR3LZ/fH/17nvlUTw8MyO779XjMA7q6uurzeX/ey3md8zrnBDzP8+Tg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODwlCP4TF+Ag4ODg4ODg4ODg4ODg4ODg4ODg4ODg4PDrwpcYMbBwcHBwcHBwcHBwcHBwcHBwcHBwcHBweFpggvMODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4PE1wgRkHBwcHBwcHBwcHBwcHBwcHBwcHBwcHB4enCS4w4+Dg4ODg4ODg4ODg4ODg4ODg4ODg4ODg8DTBBWYcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHByeJrjAjIODg4ODg4ODg4ODg4ODg4ODg4ODg4ODw9MEF5hxcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHB4muACMw4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODk8TXGDGwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHhaYILzDg4ODzl+MlPfqJAIKCf/OQnj/nej3/84woEAk/9RT1NGBgY0OWXX/5MX8aTCp7nN77xjWf6UhyeIG6++WZt3bpVkUjkSV9vP/7xj/WCF7xATU1NCgQCOnDgwPNuXT9RPB/3AwcHBwcHh6cCjj9c/kxfxpMKxx+e+3iq+MPll1+uxsbGJ+3zwGqc5NmAWq2mq666Sv39/QoGgzr//PMlPT/W/eWXX66BgYFn+jIcHJ5TcIEZBweH42J6elpXX321tm/frmQyqWg0qjVr1uiNb3yj/uVf/kWe5z0t1zEwMKBAIGD/GhsbtX79en3wgx/U+Pj403INTyXm5+d1/fXX6xWveIV6enoUjUY1ODioj33sY5qfnz+hz5ientbnPvc5nX/++ero6FBjY6O2bt2qv/iLv1ClUjnm/Z7n6X/8j/+hjRs3KhqNauPGjfqrv/qrp+2ZSlK5XFZbW5vOOuusR33fC1/4QnV0dKx6H4+Gr3zlKwoEAvrZz372y1zmswKBQEDvec97npTP2rdvny699FJ1d3fri1/8om688UZJ0ic/+Ul9+9vf/qU+u1Ao6A1veIM8z9MXvvAF3Xjjjcpms7/UZ373u9/Vxz/+8VV/92Rcs4ODg4ODg8OTB8cfnh44/uD4w2PhucIfngo8FZzkycJNN92kT33qU3rVq16lr371q7rqqqt+6c883nPYuXOnPv7xjz9rglIODg7HIvxMX4CDg8OzE/fee69e/epXa2pqSr/1W7+lt7/97YrFYhoaGtK//du/6XWve53+9m//Vu9973sf87POO+88LSwsKBKJPOHrOeWUU/TRj35UklQqlbRjxw793d/9nX70ox/p/vvvVygUesKf/Uxj3759et/73qeXvvSlev/7369MJqOf/vSnuvbaa/Vf//Vf+slPfqJg8NHj6HfccYf+6I/+SBdddJGuvPJKxWIx/fCHP9QVV1yh+++/X1/72tfq3v+JT3xCH//4x/WWt7xFV1xxhW699VZ98IMfVD6f15/+6Z8+lbdraGho0Bvf+EZdf/31euSRR7R+/fpj3vPwww/rzjvv1Ac+8AGFw+7IejJw++23q1Kp6LOf/axOO+00e/2Tn/yk3vzmN+t1r3vdE/7se++9V7lcTl/+8pd/qc/x47vf/a6++MUvrhqceTKu2cHBwcHBweHJgeMPTx8cf3D84enEU8kfngo8FZzkycKPf/xjtbS06G//9m+ftMyj4z2HnTt36s/+7M90/vnnPy2ZLH//93+vWq32lH+Pg8PzCe6UcnBwOAYzMzO65JJLVKvVdPfdd2vbtm11v//TP/1T3Xrrrcrlco/6OfPz84rFYgoGg790enJXV5cuvfTSutdaW1v1iU98Qjt27ND27dt/qc9/JtHZ2an7779fJ598sr32zne+Uxs3btTHPvYxfe9739PFF1/8qJ9x0kkn6eGHH64zuN7znvfoPe95j774xS/qyiuvtM8fHR3VNddco7e97W36X//rf0mS3vGOdygUCulTn/qU3vWud6mzs/PJv9FVcOmll+r666/XTTfdpKuvvvqY39900032vl81VKtVVavVX8ohsRrGxsYkSS0tLU/q5z7Vn+3g4ODg4ODw7IXjD08vHH9w/GE1PBf5w1OBp+J62Zt+WYyNjSmVSj2vyi+ChoaGZ/oSHByec3ClzBwcHI7BF7/4RQ0NDelzn/vcMaQKvPSlL61TZJD2fcstt+hDH/qQOjs7FY/HJR2/RvT3vvc9nXrqqWpsbNTGjRvNyD9RtLe3S1KdEmp6elof/ehHdcopp6i5uVmJREIXXHCB/uu//uuYv//mN7+pM888U8lkUqlUSieffLI++clP1r2nWCzqiiuu0Nq1a60Uwx/90R9pcXGx7n1LS0u68sor7b4vvPBC7d69+4Tuo62trY5Ugd/8zd+UJD3wwAOP+Rlr165dVQWz2mf8y7/8ixYXF/X+97+/7r3vf//7tbi4qH/5l385oev2o1Kp6M1vfrOampr0/e9/X9JyuYPrr79ep556qpqampTJZPS7v/u7Ghoasr978YtfrMHBQSNQK/EP//AP2rhxo84888zHfU0nip07d+qSSy5RS0uLYrGYXvziF+vf/u3f7Pee56mtrU3/7b/9t7q/6+vrUyAQ0L59++y1m2++WYFAQDt37rTXxsbG9O53v9vKTGzYsEHXXnttXdmHAwcOKBAI6NOf/rSuv/56bdiwQdFoVHfccccJ38eJjPfAwICuvPJKSctzJhAI6PLLL1cgENDi4qK++tWvWskP6h2fKM4//3y96U1vkiRdcMEFj/kZ3/nOd3TxxRert7dX0WhU/f39uvLKK+vW1uWXX64vfvGLklRXjoTxerRrPtG1S5mHH/zgB9q+fbsaGxu1YcMGff3rXz/mmp+O/cDBwcHBweG5CMcfjsLxhxOD4w/L+FXmD34cPHhQr371q5VIJNTe3q4//MM/1NLS0jHv+8d//EedffbZisfjSqVSuvjii/Xggw/a7x+Lk/znf/6nXvaylymRSKi5uVkvf/nLdeedd9Z9x6PtTZJ0zz336OKLL1Zra6uampr0whe+UN/97ncf9f54Xj/4wQ908OBBG7OvfOUrq75/aWlJV199tc4880z7nrPOOkvf+c536t53vOfwla98Rb/9279dNw4rv+9E7oOxuP322/XHf/zH6urqUlNTk17+8pdr//79de9drcfM4+FaDzzwgC688ELFYjF1dnbqiiuu0L//+7+fcL8xB4fnIlzGjIODwzH4zne+o8bGRv3Wb/3W4/7b97///WptbdVVV12lfD5/3Pf9+Mc/1mtf+1qtX79ef/7nf65SqWQH/Wool8uanJyUJC0uLur+++/Xtddeq+3bt+ukk06y9+3bt0//+I//qDe84Q1av369ZmZm9L/+1//Sr/3ar+muu+4yovgf//EfevOb36yXvexluuaaaxQKhfTQQw/p9ttvt88qlUq64IILtHfvXr3rXe/S4OCg7rvvPn3uc5/T7t276+q4vvvd79ZXvvIVveENb9AFF1ygO++8U7/+67+uUqn0uMcQDA8PS1omXk/mZ9x9992KRqM65ZRT6t67fft2RSIR3XPPPY/rOxYXF/XGN75RP/rRj/S9731PL3vZyyQtz4W/+7u/01ve8ha9973v1ejoqL7whS/ojjvu0L333msKpt/93d/VJz7xCd155511BOrnP/+5Hn74YX3iE594Ird+QtizZ4/OOeccRaNR/cEf/IESiYRuuOEGvepVr9K3vvUtXXLJJQoEAjr33HN166232t/t379fQ0NDCgaDuvXWW7Vu3TpJ0m233aZ0Om1zcnJyUmeffbYWFxf1rne9S11dXbr99tt15ZVXanh4WH/5l39Zdz1f+9rXNDc3p3e9611KJBLHXQ+r4UTG+y//8i/1jW98QzfffLM+//nPq62tTYODg7rwwgv1tre9TWeffbbe9a53SZI6Ojoe11heddVV2rZtm/7mb/5Gf/zHf6wtW7Y86md8+ctfVigU0u///u+rtbVVP/vZz/S5z31OQ0NDRrTf/e536/Dhw/rxj39stawlKZvN6sYbbzzuNT+etStJP/vZz/Stb31L733ve/X2t79dX/rSl3TppZdq+/bt2rx58+P+zKdiP3BwcHBwcHg2w/GHZTzT9oLjD44/PJf4A6jVanrFK16h0047TZ/5zGf0n//5n7ruuus0PT2tG264wd732c9+Vh/96Ef1+te/Xm95y1s0Ozurv/3bv9U555yje+65R2vXrn1UTnLbbbfp13/919Xb26s/+ZM/Ua1W09/93d/ppS99qW699dZjgnmr7U233367Xv7yl2vbtm266qqrFI1GdfPNN+uSSy7RP/3TP+n1r3/9qvcIf/mLv/gLDQ8P6/Of/7yk5UDjaigUCrr++uv1pje9SW9961tVKpX0D//wD3rd616nH/zgB7rooosk6bicaHBwUO973/vqxsH/fY/3Pv7gD/5AjY2N+tjHPqbJyUl99rOf1e/+7u+eUCDwRLjWyMiIXvrSl6pSqegjH/mI0um0vva1r+mHP/zhY36+g8NzGp6Dg4PDCqTTae/UU0895vXZ2VlvYmLC/uXzefvdDTfc4EnyzjrrLK9cLtf93S233OJJ8m655RZ77fTTT/fa2tq8qakpe+3BBx/0QqGQt3Jr6u/v9yQd8++MM87whoeH695bKpWLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1650x814 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1650x814 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"for region, boxes in REGIONS.items():\n",
|
||||
" box = boxes['roi']\n",
|
||||
" fig, axes = plt.subplots(1, 2, figsize=(15, 7.4))\n",
|
||||
" for ax, img, name in ((axes[0], images[region]['roi']['GridBased 2-20 keV'], 'flattened'),\n",
|
||||
" (axes[1], images[region]['roi_raw_grid'], 'before flattening')):\n",
|
||||
" low, high = limits(img)\n",
|
||||
" ax.imshow(img, cmap='gray', extent=[box[0], box[1], box[2], box[3]], vmin=low, vmax=high)\n",
|
||||
" ax.set_title(f'GridBased 2-20 keV, {region}, {name}', fontsize=11)\n",
|
||||
" ax.set_xlabel('x [pixel, 25 um]'); ax.set_ylabel('y [pixel, 25 um]')\n",
|
||||
" fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "318433ac",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2. Profiles and FRC\n",
|
||||
"\n",
|
||||
"A row through the zoom (normalised to its mean), and the one-image Fourier ring\n",
|
||||
"correlation as `SiementStar_LowerLeft.ipynb` computes it (`frc.one_frc` and\n",
|
||||
"`frc.frc_res` on the 50 × 50 px box x 162–212, y 140–190, no window; for\n",
|
||||
"LowerRight the same box around its star). The cutoffs are in that notebook's\n",
|
||||
"units, so they compare with its ML 2.041 / eta 2.053 for LowerLeft."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "6162c863",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T10:33:43.677997Z",
|
||||
"iopub.status.busy": "2026-09-28T10:33:43.677903Z",
|
||||
"iopub.status.idle": "2026-09-28T10:33:43.883956Z",
|
||||
"shell.execute_reply": "2026-09-28T10:33:43.883755Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAABfYAAAHCCAYAAACt2ZiFAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AAEAAElEQVR4nOzdd3wU5dbA8d/M7iab3ulVpakgWADLpdsB21VREOEFUbBduRYsKIpiBdu1NxABr2AB7ICA5aqAilJEEAgtlPS+beZ5/9hCQtoGEnYTztfPfkxmZ555ZmY3zJw5cx5NKaUQQgghhBBCCCGEEEIIIUSDoIe6A0IIIYQQQgghhBBCCCGECJ4E9oUQQgghhBBCCCGEEEKIBkQC+0IIIYQQQgghhBBCCCFEAyKBfSGEEEIIIYQQQgghhBCiAZHAvhBCCCGEEEIIIYQQQgjRgEhgXwghhBBCCCGEEEIIIYRoQCSwL4QQQgghhBBCCCGEEEI0IBLYF0IIIYQQQgghhBBCCCEaEAnsCyGEEEIIIYQQQgghhBANiAT2hRBCCCGEEEIIIYQQQogGRAL7QgjRQG3fvp1LL72UtLQ0NE1j1KhRoe6SEEIIIYQQx6x+/frRrl27w14+PT0dTdOYMmVKnfVJCCFE4yWBfSFEWFixYgWapvHoo4+Guit1bubMmWiaxnvvvVen7Y4aNYqVK1dyzz33MHv2bG688UbWrl3LlClTSE9Pr9N1ieD99ddf3HXXXQwaNIiUlBQ0TWPs2LFVzu/xeHjqqac4+eSTsdvtJCUlcfHFF7NmzZoql3njjTc45ZRTiIqKIi0tjWuvvZYdO3bUx+YIIYQQQlTpWDiHL/uKi4vjjDPO4IUXXsAwjFB3kRUrVjBlyhTy8vJC3ZVj1qpVq7j99tvp06cP8fHxNX4fnE4nL774IqeddhpJSUkkJCTQrVs3Hn/8cYqKiirM7/F4ePLJJ+nUqRORkZG0aNGC8ePHk52dXZ+bJYRoICSwL4QQDZDT6eS7777juuuu484772TEiBGceeaZrF27locfflgC+yH0448/8swzz7Bt2zbOOOOMaudVSnHZZZdxzz33kJaWxtNPP82kSZPYtGkT55xzDt99912FZSZPnsy4ceOIi4vjueee4/bbb2fJkiWceeaZ7N69u742SwghhBDimDR+/Hhmz57Nu+++y+TJkykpKeH222/n5ptvrjDv119/zV9//XXU+rZixQoefvhhCeyH0Oeff85//vMfMjMzOfXUU2ucf9iwYdx22220adOGxx57jGnTptG2bVvuu+8+Lrzwwgrzjx49mkmTJtGxY0f+85//MHr0aN5991369OlDYWFhfWySEKIBsYa6A0II0VgVFxcTExNTL23v378fpRTJycn10n516nO7GoMhQ4aQk5NDUlIS6enptG/fvsp5Fy1axKeffsr555/PF198gaZpANx444107tyZG264gT///DMwffPmzTz++OOceuqprFixAqvV+8/4xRdfzOmnn859993Hu+++W/8bKYQQQgjRSB16rnvWWWcxYsSIwO8TJkygS5cuvPHGG0ydOpW0tLTAexEREUe1r/VNKUVpaSnR0dGh7krYGj9+PHfeeSexsbGsWLGC/v37Vznv33//zSeffMLll1/Ohx9+GJh+8803M2TIED799FM2bNjASSedBMA333zDe++9x9ChQ1m4cGFg/p49e3LppZfy9NNP88gjj9Tfxgkhwp5k7AshGpxNmzYxbNgwmjZtSmRkJMcddxx33nknBQUFgXn27NmDpmn8+9//LrfsuHHj0DSNG2+8sdz0iRMnomka+/fvD0xzuVw89dRTdOvWjaioKOLj4xk0aBDffvttuWXL1sL88MMP6dmzJ9HR0Vx88cW13ratW7cyatQoWrRoQUREBK1atWLChAlkZWUF5unXrx9t27YF4OGHHw48GtyuXTtGjx4NQP/+/QPTy9be37lzJ5s2bcLtdtfYF/+j1TNnzuS1116jW7du2O32ctlJc+bMoVevXsTGxhITE0Pv3r15//33y7Xz2GOPoWka69atC0xzu93ExsaiaRo//vhjYLpSitTUVC666KJq+3bxxRcTFRVFbm5uhfcyMjKwWq0MGzasxm2sDykpKSQlJQU17zfffAN4yyr5g/cAiYmJXHLJJfz111/88MMPgelz587FMAxuu+22QFAfoEePHvTv358FCxZQWlpa43r9n4vly5dz9tlnExMTQ2pqKqNHjyYzMzMwn2EY9O3bF7vdzq+//lqh7xaLhUsvvTSobRVCCCHEsa2xnMPHxsbSq1cvTNNk69at5d6rqsb+l19+Sa9evYiKiqJJkybccMMN5OTkVDtO1hdffEHv3r0Dy9x0002UlJSUW9fDDz8MQPv27QPn/mXr82/dupVNmzZVuz1+/tJDS5cu5fHHH6djx45ERkby1FNPAWCaJi+88EKgHGR8fDwDBgxgyZIl5dq54YYbsFqt5Z4iyMjICPRv7969gel5eXlYLBYmTJhQbd9OPvlkWrZsWWn5o59//hlN05g0aVJQ21nXmjZtSmxsbFDz5ufnA9CyZcsK77Vq1Qqg3E0Uf8LOxIkTy817ySWXcMIJJwSV0FP2c75gwQJOPfVUoqKiaNGiBXfccQfFxcWBeYuKiujcuTMpKSns2rWrXDuzZs1C0zT+9a9/BbWtQoijQzL2hRANytq1a+nTpw+GYTB+/HiOO+44vv/+e6ZPn87SpUv53//+R3R0NC1btqRz584sXbq03PLLli1D1/VKp5988sk0bdoU8NYyvOiii1i5ciXXXHNN4ET6vffeY8CAAXzyyScMHjy4XBsLFy7kueee46abbuKGG25AKVXrbevXrx/R0dH83//9H23btmXLli288sorLFu2jFWrVpGQkMD999/PpZdeyh133MFll13G5ZdfDkDr1q2ZO3cur7/+Ovfddx9dunQB4Pjjjw+sY+TIkaxcuZLt27cHPbDX888/z/79+xk3bhwtW7YkLi4OgAcffJCpU6fSrVs3Jk+eDMB7773HNddcw7Zt27jvvvsAGDRoEA888ABLly6la9euAPz0008UFxcHjsWZZ54Z2AfZ2dkMHDiw2j7ddNNNfP7558yePZvbbrut3HvvvPMOhmFwww031Lht+fn5Qd3kALDZbCQkJAQ1b7CcTidApVlQ/mk//fQT55xzDuC9cAFv5tihzjrrLJYtW8a6devo2bNnjev+7bffWLBgAaNHj2bEiBH8/PPPzJw5k1WrVrF69Wqio6OxWCzMmzeP7t27c9VVV/Hrr78SHx/PgQMHGD58OK1bt+add9457O0XQgghxLGhsZ3D+wP6KSkpNc67aNEiLrvsMpo3b86kSZNISkpi4cKFXHDBBVUu88UXX/Cf//yHG2+8kVGjRrFs2TJee+01AF599VUA7r//fpKTk/n444959tlnSU1NBaBbt26BdgYOHMiOHTtqdV1y1113UVpayvXXX09aWhqtW7cGvIkos2fP5pxzzuHxxx+nsLCQN998k/PPP59333038FTDoEGDePPNN1m+fDmXXXYZ4D1O/iSWpUuXct111wGwfPlyTNOs8dz/xhtv5LbbbuOzzz5j6NCh5d578803axzTyi83NzfosRHsdnvQAftgnXTSSbRo0YI333yTbt26MXDgQJRSfPXVV7zzzjuMGTOm3NO+P//8M7qu07t37wptnXnmmcyePZsDBw7QpEmTGtf96aefMmPGDCZMmMCYMWNYunQpzz33HH/88QdLlixB13ViY2P54IMP6NWrF1dffTXffvstVquVP//8k5tvvpnTTz89cKNHCBEmlBBChIHly5crQE2dOrXa+f7xj38oTdPUjz/+WG76ww8/XGH5m2++WWmapvbv36+UUmr79u0KUNddd50C1LZt25RSSh04cEBpmqZuv/32wLLPPfecAtRHH31Ubj0ul0v16NFDtW/fPjDN367ValUbNmyo0Od33nlHAWr27NnVblv37t1V+/btVXZ2drnpP/30k9J1XU2ZMqXCOh966KFK17V8+fJK19G3b18FqO3bt1fbF6UOHpOkpKTAPvTbvHmz0nVdnXrqqaqkpCQwvaioSJ188snKYrEE1uHxeFRCQoK66KKLAvM99NBDKikpSQ0ePFj16dMnMP3pp59WgPrtt9+q7ZthGKpNmzaqa9eu5aabpqnat2+vjj/+eGWaZo3b6N8fwbz69u1bY3uH8h+nMWPGVPr+Cy+8oIBynz3/dvTo0UMB6tZbbw1MP/nkkxVQbp/7vfbaawpQH374YY398m/T/Pnzy01/6qmnKv0efvnll0rTNHXllVcqwzDUoEGDlM1mUz/99FON6xJCCCFE43UsnMO/8sorKjMzUx04cED9/vvvaty4cQpQvXv3rrBM3759Vdu2bQO/ezwe1aZNGxUfH68yMjIC0w3DUJdccokC1PXXX1+hT1FRUWrr1q3l2j7//POVzWZTRUVFgWkPPfRQtef2bdu2VcGGffzb26FDh3LrUEqpZcuWKUANHjxYeTyewPQDBw6oJk2aqMTERFVYWBiYpmmamjBhQmC+66+/Xp1yyimqW7duauTIkYHpN998s9J1vcL1z6Hy8vJUdHS0GjJkSLnphYWFKjY2Vg0YMCCobfTvj2BeZY9LsIL5Pvzyyy/qlFNOKbcuXdcrXSY2NlY1adKk0nbuvfdeBahffvml2j75P1Oapqmff/653Hs333xzpdep/uuKO++8U5WUlKiTTz5ZJSQkVPhMCiFCT0rxCCEajMzMTL777jvOP//8ClkLd955JzExMeVqFfozIPzlTpYtW4bFYuHhhx/GYrGwbNkywFtSRClVLlNk9uzZtGvXjn/84x9kZWUFXvn5+QwdOpTt27ezefPmcn24+OKLOfHEEw9r29avX8/atWsZNmwYpmmWW+fxxx9Phw4d+Oqrrw6r7bJWrFiBUirobH3wZvkLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1540x462 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"fig, axes = plt.subplots(1, len(REGIONS), figsize=(7 * len(REGIONS), 4.2))\n",
|
||||
"for ax, region in zip(np.atleast_1d(axes), REGIONS):\n",
|
||||
" box = REGIONS[region]['zoom']\n",
|
||||
" for name, img in images[region]['zoom'].items():\n",
|
||||
" if img is None or name.startswith('native'):\n",
|
||||
" continue\n",
|
||||
" row = img[img.shape[0] // 2]\n",
|
||||
" ax.plot(box[0] + (np.arange(len(row)) + 0.5) / B, row / row.mean(), lw=1, label=name)\n",
|
||||
" ax.set_xlabel('x [pixel, 25 um]'); ax.set_ylabel('intensity / mean')\n",
|
||||
" ax.set_title(f'{region}: row y = {(box[2] + box[3]) / 2:.0f} px'); ax.grid(alpha=.3); ax.legend(fontsize=8)\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "81b5a618",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T10:33:43.885036Z",
|
||||
"iopub.status.busy": "2026-09-28T10:33:43.884951Z",
|
||||
"iopub.status.idle": "2026-09-28T10:33:44.783796Z",
|
||||
"shell.execute_reply": "2026-09-28T10:33:44.783573Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"DIPlib -- a quantitative image analysis library\n",
|
||||
"Version 3.5.1 (Jul 5 2024)\n",
|
||||
"For more information see https://diplib.org\n",
|
||||
"region reconstruction FRC cutoff: median range crossed\n",
|
||||
"LowerLeft eta interpolation 2.053 2.053-2.053 2/10\n",
|
||||
"LowerLeft cluster CNN 1ph 2.045 2.045-2.045 1/10\n",
|
||||
"LowerLeft cluster CNN <=3ph 2.050 2.020-2.079 2/10\n",
|
||||
"LowerLeft GridBased 2-20 keV nan nan-nan 0/10\n",
|
||||
"LowerRight eta interpolation nan nan-nan 0/10\n",
|
||||
"LowerRight cluster CNN 1ph nan nan-nan 0/10\n",
|
||||
"LowerRight cluster CNN <=3ph nan nan-nan 0/10\n",
|
||||
"LowerRight GridBased 2-20 keV nan nan-nan 0/10\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAABfgAAAHCCAYAAACzEKg2AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AAEAAElEQVR4nOzdd3gURQPA4d/eXXKX3gshpAChJlQpAtIRpHeQLk2xoah06V2KFBVFlI58IB3pTVCQIkE6AVIIAVJJIfXu5vsj5ORIQg1N5n2eUzI7OztbLpmZnaIIIQSSJEmSJEmSJEmSJEmSJEmSJL1UVM87A5IkSZIkSZIkSZIkSZIkSZIkPTrZwC9JkiRJkiRJkiRJkiRJkiRJLyHZwC9JkiRJkiRJkiRJkiRJkiRJLyHZwC9JkiRJkiRJkiRJkiRJkiRJLyHZwC9JkiRJkiRJkiRJkiRJkiRJLyHZwC9JkiRJkiRJkiRJkiRJkiRJLyHZwC9JkiRJkiRJkiRJkiRJkiRJLyHZwC9JkiRJkiRJkiRJkiRJkiRJLyHZwC9JkiRJkiRJkiRJkiRJkiRJLyHZwC9JkiRJkiRJkiRJkiRJkiRJLyHZwC9J0kstNDSU1q1b4+bmhqIo9OrV63ln6Znz8/Ojbt26zzsb9zVu3Djc3NxITk5+3lmRpCcSFhaGVqvll19+ed5ZkSRJkqQXWt26dfHz83vs/cPCwlAUhTFjxhRYnv5LXoa6T+/evSlbtixGo/F5Z0WSnsiff/6JSqXi0KFDzzsrkpQn2cAvSS+Qffv2oSgKEyZMeN5ZKXCLFi1CURSWLVtWoOn26tWL/fv3M2TIEJYuXcq7775LcHAwY8aMISws7InTHzNmDIqi5PuJjIwE/q2A3P3R6XSUKFGCzz77jISEhDzTT0pKYurUqdSsWRNnZ2csLCzw8PCgSZMmLFiwgIyMjCc+h+ctKiqKadOmMWzYMOzs7Ezh169fZ+TIkTRt2pRChQqhKAoNGzZ8YHpr1qyhXr16ODo6YmVlRfHixXNVbkJCQhgzZgw1a9bE09MTGxsbypQpw8cff8z169ef6HwSEhKYO3cuTZs2xdfXF51Oh7+/P+3bt+fEiRO54qekpDBu3Dhat26Nr68viqJQvHjxPNMWQrB8+XK6du1KyZIlsbGxoVChQtSrV49169YhhHiivD/uNc8xb968XM/+vdauXUv16tWxsbHBycmJFi1a8M8//zxRvgFWr15Nnz59qFixIpaWliiKwsGDB/ONHxoaSs+ePSlUqBBarRY/Pz8+++wzkpKS8owfFxfHgAED8PLyQqvVUrJkSaZOnYperzeL5+fnR58+fRgyZAhpaWlPfF6SJEnSf8erUJa/+2NnZ0eVKlWYM2cOBoPheWeRffv2MWbMGG7duvXEafXq1Svf8r9GozE75r3bra2tCQoKYty4cfmWFaKjoxk5ciSVK1fG0dERS0tLChcuTOvWrVm1atV/okH8xIkTLF68mPHjx6NS/dv0tGnTJvr27UvZsmWxs7PDzc2N119/nZ9++ilXuSuH0Wjkhx9+oHr16tjZ2WFra0uZMmUYOnSoWbxLly7RrVs3SpcubaorlChRgv79+3P58uUnOh+DwcCAAQN47bXXcHNzQ6vV4uPjQ8uWLfn9999zxX/UcvfXX39N/fr18fLyQqfT4e7uTs2aNVmyZMkTf78uXLjAF198QcOGDXFxcUFRFPr27fvQ+3/++ee5nv17LViwgPLly2NlZYWbmxtdunQhPDz8ifIN8MMPP9C9e3fKli2LRqO5bz0E4OTJk7Rt2xZXV1dTmX78+PH51qvDw8Pp0qULbm5uWFlZUb58eRYsWJArXo0aNWjSpAmffPLJE9fJJOlpyP/bKUmS9ILLyMjgwIEDfPjhh3z++eem8EWLFjF27Ngn7jV0ty+//JISJUrkCnd2djb7uW7duvTp0weA+Ph4tm3bxsyZM9m5cyfHjh3D0tLSFPfEiRO0bNmSa9eu8dZbbzFixAicnZ2Jjo5m9+7dvPvuuxw9epQffvihQM7heZk2bRqKovDuu++ahV+4cIGJEydSuHBhqlSpwqZNmx6Y1gcffMB3331HixYtGD9+PFZWVly9epU///zTLN7ChQuZM2cOzZo1o0OHDlhbW3P48GG+/fZbli9fzh9//EGpUqUe63z++usvBg4cSJ06dejfvz+enp6EhIQwf/581q1bx/Lly+ncubMpfmxsLKNHj8bd3Z2KFSsSHx+fb9oZGRl069aNMmXK0Lp1a0qUKEFsbCwLFy6kbdu2DBgwgG+//fax8g2Pd81zREREMGzYMGxtbUlJSckzzsKFC+nbty+BgYFMnTqVjIwM5s2bR82aNTl48CDly5d/7Lx/8803HD58mKCgIEqVKsWpU6fyjXvhwgVq1KhBcnIy7777LoGBgZw+fZq5c+eyf/9+Dhw4gJWVlSl+cnIytWvX5sKFC7z//vuUK1eOAwcOMHToUE6fPs3SpUvN0h80aBDfffcdP//8M++///5jn5MkSZIkvWwGDBhAjRo1EEJw/fp1Fi9ezMCBAzl79izz5883i7tjx45n2hC2b98+xo4dS69evXB0dCyQNOfMmYOTk5NZ2N2N1Tnat29Pq1atAIiJieF///sfo0eP5s8//2Tbtm1mcXfu3EmnTp1ITk6mbdu29OjRAzs7O65du8a2bdvo3Lkzly9fZvjw4QVyDs/L2LFj8fPzo02bNmbh/fr1w8rKilatWlG2bFmSkpL45Zdf6NOnD2vXrmXTpk0oimKKr9fradeuHb/99hudOnUyvXwJCwvL1aErMjKSa9eu0bp1awoXLoxWq+XixYv89NNP/PLLL/zxxx8EBQU91vno9Xr++usvatSoQdeuXXFwcCAqKoply5ZRp04dfvrpJ9555x1T/Ectdx85cgRvb2+aNGmCq6srSUlJbN68mZ49e7Jnzx4WLVr0WPkGOHToENOnT8ff358qVaqwffv2h9732LFjfP3119ja2ub7wurLL79kwoQJ1KxZk6+//pqYmBhmz57Nvn37TOf1uCZNmkRsbCwVKlTAz8/vvi9qDh48SMOGDbGwsOCDDz7A39+fQ4cOMXr0aP76669cz1ZkZCTVq1cnMTGRTz75BH9/fzZt2kT//v2JiIhg/PjxZukPGjSIRo0asXXrVpo2bfrY5yRJT4WQJOmFsXfvXgGI8ePHP++sFJiUlBQhhBA///yzAMTSpUsLLO3w8HABiNGjR5uF5xxr7969T3yM0aNHC0AcOHDgvvFCQ0MFIPr06ZNrW6tWrQQg1qxZYwq7efOmKFSokLCxsRG7d+/OM83g4GAxffr0B+bR19dX1KlT54HxnoeUlBTh4OAg3nnnnVzbkpKSxM2bN00/A6JBgwb5prVkyRIBiB9++OGBxz169KiIj4/PFf79998LQHTo0OEhzyC30NBQceHChVzhp06dEhYWFsLT01MYDAZTeHp6uoiIiDD97OvrK4oVK5Zn2llZWWLXrl25wlNSUkRAQIAAxJkzZx477496ze/WpEkTUblyZdGtWzcBiKtXr5ptj4+PF/b29sLb21skJiaawq9evSrs7OzEG2+88dj5FkKIsLAwkZmZKYR48PeydevWAhArVqwwC1+xYoUAxMSJE83Cv/zySwGIGTNmmIV/8sknAsjzO1qjRg0RGBj4JKckSZIk/ce8imX55ORk4e3tLVQqlYiOji7QY+eUr+8t6+cnp3wQGhr6xMfu2bNnnuWde+V3z/V6vahcubIAxLFjx0zh586dEzY2NsLT01MEBwfnmeaePXvEwoULH5hHQPTs2fPBJ/MchIWFCbVaLcaOHZtr286dO4XRaDQL0+v1olatWgIQW7ZsMds2btw4oVKpxLZt2x47P4cPHxZAnnWSJ5WUlCTc3NyEv79/rvDHLXff7a233hKACA8Pf+w8xsbGmupG96u33iszM1MEBQWJ1q1bizp16gi1Wp0rzoULF4RarRaVKlUSWVlZpvC///5bqFQq0b1798fOtxBCXLlyxVS3etD3skKFCkJRFHHw4EGz8EmTJglALF++3Cy8e/fuAhC//vqrWXibNm2EWq0WFy9eNAs3GAzC29tbNGvW7InOSZKeBjlFjyS9pM6fP0/nzp3x8PBAq9VStGhRPv/8c7PpJ65du4aiKHz22Wdm+/bv3z/PHtWDBg1CURRu3rxpCsvMzGTatGmUK1cOKysr7O3tadiwYa5hiHfPkfnrr79StWpVrK2tadas2SOf2+XLl+nVqxdeXl5YWlri7e3N+++/T2xsrClO3bp18fX1BbJ7h+QMifXz8zP1nKhXr54p/HnOT5kzFDMkJMQU9tVXX3H9+nWmTJlC/fr189yvfPnyue7d/Zw8eZI333wTOzs7HBwcaNeuHaGhobnipaenM3bsWEqVKoVOp8PZ2ZkWLVpw7NgxU5yoqCjc3d0pXrx4rilNcqYt+vrrrx+Yp61bt5KYmJjnc2BnZ4e7u/tDn9/48eMpX748/fr1A7J7Xec3fPm1117L1dsKMPWsf5IpY/z8/PIczREYGEhgYCA3btwgOjraFK7VailSpMhDpa3RaGjQoEGucBsbG5o3bw48Wd4f9ZrnWLJkCTt37mTBggWo1eo842zYsIGkpCT69u2Lvb29Kdzb25uOHTty4MCBJ5o2y9fXFwsLi4eKu2fPHqysrMxGUgB06tQJnU7HTz/9ZBa+ZMkSrKysGDBggFl4zvdvyZIluY7RtGlTTp8+zenTpx/lNCRJkiQJ+O+U5W1tbalWrRpGozFXz9r8RtNu27aNatWqYWVlhbu7O/369SM+Pv6+ZfatW7dSvXp10z7vvfceqampZscaO3YsAP7+/qY6wPOav1+tVpvWyLq7DvDll19y+/Zt03QmealXrx69e/d+6GPt3buXmjVrYmNjg6urK++88w4xMTG54t26dYtBgwbh7++PVqvFw8ODt99+2yx/p06Line truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1540x462 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# one_frc splits the counts binomially with its own (unseeded) generator, so one\n",
|
||||
"# call is one draw: repeat it and quote the median and the range\n",
|
||||
"N_REPEAT = 10\n",
|
||||
"frc_results = {}\n",
|
||||
"try:\n",
|
||||
" import frc\n",
|
||||
" fig, axes = plt.subplots(1, len(REGIONS), figsize=(7 * len(REGIONS), 4.2))\n",
|
||||
" for ax, region in zip(np.atleast_1d(axes), REGIONS):\n",
|
||||
" frc_results[region] = {}\n",
|
||||
" for name, img in images[region]['frc'].items():\n",
|
||||
" if img is None or name.startswith('native'):\n",
|
||||
" continue\n",
|
||||
" square = frc.util.square_image(np.array(img, float), add_padding=False)\n",
|
||||
" size = square.shape[0]\n",
|
||||
" values, first = [], None\n",
|
||||
" for _ in range(N_REPEAT):\n",
|
||||
" curve = frc.one_frc(square)\n",
|
||||
" xs = np.arange(len(curve)) / size\n",
|
||||
" first = curve if first is None else first\n",
|
||||
" try:\n",
|
||||
" values.append(float(frc.frc_res(xs, curve, size)[0]))\n",
|
||||
" except Exception: # the curve never crosses 1/7\n",
|
||||
" values.append(np.nan)\n",
|
||||
" values = np.array(values)\n",
|
||||
" found = np.isfinite(values)\n",
|
||||
" frc_results[region][name] = dict(\n",
|
||||
" median=float(np.median(values[found])) if found.any() else np.nan,\n",
|
||||
" low=float(values[found].min()) if found.any() else np.nan,\n",
|
||||
" high=float(values[found].max()) if found.any() else np.nan,\n",
|
||||
" crossings=int(found.sum()), repeats=N_REPEAT)\n",
|
||||
" r = frc_results[region][name]\n",
|
||||
" ax.plot(np.arange(len(first)) / size, first, lw=1,\n",
|
||||
" label=f\"{name}: {r['median']:.3f} ({r['crossings']}/{N_REPEAT} crossed)\")\n",
|
||||
" ax.axhline(1 / 7, color='k', lw=.6, ls=':')\n",
|
||||
" ax.set_xlabel('spatial frequency (1/pixels)'); ax.set_ylabel('FRC')\n",
|
||||
" ax.set_title(f'{region}, FRC box {REGIONS[region][\"frc\"]}'); ax.grid(alpha=.3); ax.legend(fontsize=8)\n",
|
||||
" fig.tight_layout()\n",
|
||||
" print(f\"{'region':11s} {'reconstruction':20s} {'FRC cutoff: median':>18s} {'range':>15s} {'crossed':>8s}\")\n",
|
||||
" for region, values in frc_results.items():\n",
|
||||
" for name, r in values.items():\n",
|
||||
" print(f\"{region:11s} {name:20s} {r['median']:18.3f} {r['low']:7.3f}-{r['high']:.3f} \"\n",
|
||||
" f\"{r['crossings']:5d}/{r['repeats']}\")\n",
|
||||
"except Exception as error:\n",
|
||||
" print('FRC skipped:', repr(error))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "533a651d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3. Photon statistics\n",
|
||||
"\n",
|
||||
"Photons in each whole region. The cluster chains keep only clusters that fall in\n",
|
||||
"the 1/2/3-photon energy windows; at this occupancy the rest is lost to pile-up\n",
|
||||
"(`SiementStar_LowerLeft.ipynb`: 45 % of the photons are in single-photon\n",
|
||||
"clusters)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "47cb5a91",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T10:33:44.785013Z",
|
||||
"iopub.status.busy": "2026-09-28T10:33:44.784889Z",
|
||||
"iopub.status.idle": "2026-09-28T10:33:44.798000Z",
|
||||
"shell.execute_reply": "2026-09-28T10:33:44.797767Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"region eta (1ph) CNN 1ph CNN <=3ph GridBased photons per frame: GridBased / CNN <=3ph\n",
|
||||
"LowerLeft 1.4060e+09 1.4060e+09 1.6677e+09 3.8487e+09 192.4 / 83.4 = 2.31\n",
|
||||
"LowerRight 2.7039e+09 2.7039e+09 4.4703e+09 1.3339e+10 667.0 / 223.5 = 2.98\n",
|
||||
"(GridBased over 20,000,000 frames; the cluster chains used all 20 M)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"counts = {}\n",
|
||||
"CLUSTER_FRAMES = 20e6 # the cluster chains used the whole run\n",
|
||||
"print(f\"{'region':11s} {'eta (1ph)':>12s} {'CNN 1ph':>12s} {'CNN <=3ph':>12s} {'GridBased':>12s} \"\n",
|
||||
" f\"photons per frame: GridBased / CNN <=3ph\")\n",
|
||||
"for region in REGIONS:\n",
|
||||
" c = {name: float(np.nansum(img)) for name, img in images[region]['roi'].items()\n",
|
||||
" if img is not None and not name.startswith('native')}\n",
|
||||
" counts[region] = c\n",
|
||||
" cnn = c.get('cluster CNN <=3ph', np.nan)\n",
|
||||
" print(f\"{region:11s} {c['eta interpolation']:12.4e} {c.get('cluster CNN 1ph', np.nan):12.4e} {cnn:12.4e} {c['GridBased 2-20 keV']:12.4e} \"\n",
|
||||
" f\"{c['GridBased 2-20 keV'] / frames.sum():8.1f} / {cnn / CLUSTER_FRAMES:6.1f} = \"\n",
|
||||
" f\"{(c['GridBased 2-20 keV'] / frames.sum()) / (cnn / CLUSTER_FRAMES):.2f}\")\n",
|
||||
"print(f'(GridBased over {frames.sum():,.0f} frames; the cluster chains used all 20 M)')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b2edee48",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4. Energy spectrum from the energy head"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "75e762b8",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T10:33:44.799203Z",
|
||||
"iopub.status.busy": "2026-09-28T10:33:44.799120Z",
|
||||
"iopub.status.idle": "2026-09-28T10:33:45.047119Z",
|
||||
"shell.execute_reply": "2026-09-28T10:33:45.046919Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"15 keV line at 15.013 keV, core sigma 0.538 keV; below 13.5 keV 12.12 %, 13.5-16.5 keV 82.46 %, above 16.5 keV 5.41 %\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 825x462 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def gauss(x, a, mu, sig):\n",
|
||||
" return a * np.exp(-0.5 * ((x - mu) / sig)**2)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"total = spectrum.sum()\n",
|
||||
"near = np.abs(spectrum_centres - 15) < 2\n",
|
||||
"peak = spectrum_centres[near][np.argmax(spectrum[near])]\n",
|
||||
"window = np.abs(spectrum_centres - peak) < 0.8\n",
|
||||
"try:\n",
|
||||
" (a, mu, sig), _ = curve_fit(gauss, spectrum_centres[window], spectrum[window],\n",
|
||||
" p0=(spectrum[window].max(), peak, 0.3), maxfev=20000)\n",
|
||||
"except Exception:\n",
|
||||
" if spectrum[window].sum() > 0:\n",
|
||||
" mu = np.average(spectrum_centres[window], weights=spectrum[window])\n",
|
||||
" sig = np.sqrt(np.average((spectrum_centres[window] - mu)**2, weights=spectrum[window]))\n",
|
||||
" else:\n",
|
||||
" mu = sig = np.nan\n",
|
||||
"fractions = dict(below=spectrum[spectrum_centres < 13.5].sum() / total,\n",
|
||||
" line=spectrum[(spectrum_centres >= 13.5) & (spectrum_centres <= 16.5)].sum() / total,\n",
|
||||
" above=spectrum[spectrum_centres > 16.5].sum() / total)\n",
|
||||
"print(f'15 keV line at {mu:.3f} keV, core sigma {abs(sig):.3f} keV; below 13.5 keV {fractions[\"below\"]*100:.2f} %, '\n",
|
||||
" f'13.5-16.5 keV {fractions[\"line\"]*100:.2f} %, above 16.5 keV {fractions[\"above\"]*100:.2f} %')\n",
|
||||
"fig, ax = plt.subplots(figsize=(7.5, 4.2))\n",
|
||||
"ax.semilogy(spectrum_centres, spectrum / total / np.diff(spectrum_centres)[0], lw=1)\n",
|
||||
"ax.axvline(15, color='grey', lw=.6, ls=':')\n",
|
||||
"ax.set_xlim(0, 30); ax.set_ylim(1e-6, 5)\n",
|
||||
"ax.set_xlabel('reconstructed photon energy [keV]'); ax.set_ylabel('photons / keV (normalised)')\n",
|
||||
"ax.set_title('Siemens star, both regions, GridBased 2-20 keV'); ax.grid(alpha=.3, which='both')\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "42d1185c",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T10:33:45.048244Z",
|
||||
"iopub.status.busy": "2026-09-28T10:33:45.048159Z",
|
||||
"iopub.status.idle": "2026-09-28T10:33:45.133257Z",
|
||||
"shell.execute_reply": "2026-09-28T10:33:45.133003Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"written /home/xie_x1/MLXID/GridBased/Results/overnight_poly2to20keV_Moench040/report/siemens_star_poly2to20keV_summary.json\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"summary = dict(parts=parts, frames=float(frames.sum()),\n",
|
||||
" photons=float(sum(s['n_photons'] for s in summaries)),\n",
|
||||
" model=summaries[0]['checkpoint'], epoch=summaries[0]['epoch'], crop=summaries[0]['crop'],\n",
|
||||
" regions={k: v['roi'] for k, v in REGIONS.items()}, photon_counts=counts,\n",
|
||||
" frc_cutoff=frc_results, line_keV=float(mu), line_sigma_keV=float(abs(sig)),\n",
|
||||
" spectrum_fractions=fractions)\n",
|
||||
"out = OVERNIGHT / 'report' / os.environ.get('GRID_STAR_SUMMARY', 'siemens_star_poly2to20keV_summary.json')\n",
|
||||
"out.parent.mkdir(parents=True, exist_ok=True)\n",
|
||||
"json.dump(summary, open(out, 'w'), indent=1)\n",
|
||||
"regions_dir = GRID / f'SiemensStar_15keV_{POLY_TAG}_regions' # the two regions as their own arrays\n",
|
||||
"regions_dir.mkdir(exist_ok=True)\n",
|
||||
"for region in REGIONS:\n",
|
||||
" np.save(regions_dir / f'{region}_binned_image_flattened.npy', images[region]['roi']['GridBased 2-20 keV'])\n",
|
||||
" np.save(regions_dir / f'{region}_binned_image.npy', cut_grid(raw, REGIONS[region]['roi']))\n",
|
||||
"json.dump(summary, open(regions_dir / 'summary.json', 'w'), indent=1)\n",
|
||||
"print('written', out)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "pytorch_nightly",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.18"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,659 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "86bf6c9c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Siemens star, 15 keV, MOENCH040 — polychromatic 2–20 keV GridBased model\n",
|
||||
"\n",
|
||||
"SOLEIL 2504 beamtime, MOENCH040 @150 V, 15 keV, 20 M frames of the full chip\n",
|
||||
"(2000 files). The two regions of `DataProcess/Configs.py` are reconstructed:\n",
|
||||
"\n",
|
||||
"| region | x [px] | y [px] |\n",
|
||||
"|---|---|---|\n",
|
||||
"| `SiemenStarLowerLeft` | 130–240 | 110–220 |\n",
|
||||
"| `SiemenStarLowerRight` | 235–345 (the notebooks use 234–344) | 110–220 |\n",
|
||||
"\n",
|
||||
"Both share the same rows, so one crop of the frame, x 126–349 and y 106–224\n",
|
||||
"(the regions plus the network's halo R = 4), is read and reconstructed in one\n",
|
||||
"pass; its valid region is x 130–345, y 110–220. Reconstruction: the 2–20 keV\n",
|
||||
"MOENCH040 model, FP16 with an FP32 head, masked column common mode (median over the pixels without charge) over the\n",
|
||||
"118 rows of the crop, self-flattening of the sub-pixel phase with one Rosenblatt table per\n",
|
||||
"local-occupancy class (tables from the first 3·10⁸ photons, every photon\n",
|
||||
"remapped; one table for the whole crop left a 25 µm grid in the dim star of\n",
|
||||
"LowerLeft, whose occupancy is ~8x below the rest). The run is processed as four parts of 500\n",
|
||||
"files; this notebook sums the parts it finds.\n",
|
||||
"\n",
|
||||
"For comparison, the published cluster-based reconstructions of the same regions\n",
|
||||
"(`SiementStar_LowerLeft/Right.ipynb`): eta interpolation (single-photon clusters)\n",
|
||||
"and the 1/2/3-photon CNNs summed (`≤3ph`), all at 2.5 µm."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "5e4befe5",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T09:23:42.386960Z",
|
||||
"iopub.status.busy": "2026-09-28T09:23:42.386752Z",
|
||||
"iopub.status.idle": "2026-09-28T09:23:42.764863Z",
|
||||
"shell.execute_reply": "2026-09-28T09:23:42.764621Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"parts found: 2 of 2 ['SiemensStar_15keV_part0', 'SiemensStar_15keV_part1']\n",
|
||||
"model 260927_poly2to20keV_Moench040_c96_00 (epoch 182), 10,000,000 frames, 7.9688e+09 photons (796.9 per frame in the 23650 px valid region)\n",
|
||||
" SiemensStar_15keV_part0 files [0, 499, 1] 5,000,000 frames occupancy 3.29 % (illuminated 5.58 %) 2434 frame/s sub-pixel rms 17.2 -> 1.2 %\n",
|
||||
" SiemensStar_15keV_part1 files [500, 999, 1] 5,000,000 frames occupancy 3.45 % (illuminated 5.88 %) 1970 frame/s sub-pixel rms 17.3 -> 1.1 %\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import json\n",
|
||||
"import os\n",
|
||||
"from pathlib import Path\n",
|
||||
"\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import numpy as np\n",
|
||||
"from scipy.optimize import curve_fit\n",
|
||||
"\n",
|
||||
"GRID = Path('/mnt/sls_det_storage/moench_data/MLXID/InferenceResults/GridBased')\n",
|
||||
"PUBLISHED = Path('/home/xie_x1/MLXID/DeepLearning/InferenceResults')\n",
|
||||
"ETA = Path('/home/xie_x1/MLXID/EtaInterpolation/Results')\n",
|
||||
"OVERNIGHT = Path('/home/xie_x1/MLXID/GridBased/Results/overnight_poly2to20keV_Moench040')\n",
|
||||
"POLY_TAG = os.environ.get('GRID_POLY_TAG', 'poly2to20')\n",
|
||||
"RUNS = [r.strip() for r in os.environ.get(\n",
|
||||
" 'GRID_STAR_RUNS', ','.join(f'SiemensStar_15keV_part{i}' for i in range(4))).split(',')]\n",
|
||||
"CNN = {1: '1ph_260616_15keV_v260511_00', 2: '2ph_260622_15keV_v260610_00',\n",
|
||||
" 3: '3ph_260623_15keV_v260611_00'}\n",
|
||||
"B = 10 # 2.5 um bins per 25 um pixel\n",
|
||||
"# region -> (x0, x1, y0, y1) in chip pixels: the whole region, the zoom of the\n",
|
||||
"# published notebooks, and the 50 x 50 px FRC box (SiementStar_LowerLeft.ipynb's\n",
|
||||
"# [1200:2100, 1400:2300][200:-200, 220:-180]; the same box around the right star)\n",
|
||||
"REGIONS = {'LowerLeft': dict(roi=(130, 240, 110, 220), zoom=(140, 190, 170, 210), frc=(162, 212, 140, 190)),\n",
|
||||
" 'LowerRight': dict(roi=(234, 344, 110, 220), zoom=(284, 324, 160, 200), frc=(263, 313, 140, 190))}\n",
|
||||
"\n",
|
||||
"plt.rcParams.update({'figure.dpi': 110, 'image.origin': 'lower', 'image.interpolation': 'nearest'})\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def run_dir(run):\n",
|
||||
" return GRID / (run + (f'_{POLY_TAG}' if POLY_TAG else ''))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"parts = [r for r in RUNS if (run_dir(r) / 'binned_image_flattened.npy').exists()]\n",
|
||||
"print(f'parts found: {len(parts)} of {len(RUNS)} {parts}')\n",
|
||||
"summaries = [json.load(open(run_dir(r) / 'summary.json')) for r in parts]\n",
|
||||
"frames = np.array([s['n_frames'] for s in summaries], float)\n",
|
||||
"flattened = sum(np.load(run_dir(r) / 'binned_image_flattened.npy').astype(float) for r in parts)\n",
|
||||
"raw = sum(np.load(run_dir(r) / 'binned_image.npy').astype(float) for r in parts)\n",
|
||||
"analog = sum(np.load(run_dir(r) / 'analog_image.npy') * n for r, n in zip(parts, frames)) / frames.sum()\n",
|
||||
"spectrum_centres = np.load(run_dir(parts[0]) / 'energy_spectrum.npy')[0]\n",
|
||||
"spectrum = sum(np.load(run_dir(r) / 'energy_spectrum.npy')[1] for r in parts)\n",
|
||||
"crop_x0, _, crop_y0, _ = summaries[0]['crop']\n",
|
||||
"print(f\"model {Path(summaries[0]['checkpoint']).parent.parent.name} (epoch {summaries[0]['epoch']}), \"\n",
|
||||
" f\"{frames.sum():,.0f} frames, {sum(s['n_photons'] for s in summaries):.4e} photons \"\n",
|
||||
" f\"({sum(s['n_photons'] for s in summaries)/frames.sum():.1f} per frame in the \"\n",
|
||||
" f\"{summaries[0]['valid_pixels']} px valid region)\")\n",
|
||||
"for s in summaries:\n",
|
||||
" print(f\" {s['run']:28s} files {s['signal_files']} {s['n_frames']:>10,d} frames \"\n",
|
||||
" f\"occupancy {s['occupancy_valid_region']*100:.2f} % (illuminated {s['occupancy_exposed']*100:.2f} %) \"\n",
|
||||
" f\"{s['frames_per_second']:.0f} frame/s sub-pixel rms {s['subpixel_nonuniformity_before']*100:.1f} -> \"\n",
|
||||
" f\"{s['subpixel_nonuniformity_after']*100:.1f} %\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "54a0702c",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T09:23:42.766071Z",
|
||||
"iopub.status.busy": "2026-09-28T09:23:42.765944Z",
|
||||
"iopub.status.idle": "2026-09-28T09:23:43.851086Z",
|
||||
"shell.execute_reply": "2026-09-28T09:23:43.850546Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def cut_grid(image, box, factor=B):\n",
|
||||
" # chip-pixel box -> the GridBased crop's binned image\n",
|
||||
" x0, x1, y0, y1 = box\n",
|
||||
" return image[(y0 - crop_y0) * factor:(y1 - crop_y0) * factor,\n",
|
||||
" (x0 - crop_x0) * factor:(x1 - crop_x0) * factor]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def cut_chip(image, box, factor=B):\n",
|
||||
" # chip-pixel box -> a full-chip super-frame (4000 x 4000 at 2.5 um)\n",
|
||||
" x0, x1, y0, y1 = box\n",
|
||||
" return image[y0 * factor:y1 * factor, x0 * factor:x1 * factor]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def published(region):\n",
|
||||
" eta = np.load(ETA / f'SiemenStar{region}_fromClusters.npy', mmap_mode='r')\n",
|
||||
" single = cnn = None\n",
|
||||
" for n, experiment in CNN.items():\n",
|
||||
" path = (PUBLISHED / f'SiemenStar{region}' / experiment / 'augX1'\n",
|
||||
" / f'{n}Photon_ML_superFrame_etaInterpolated.npy')\n",
|
||||
" if path.exists():\n",
|
||||
" image = np.asarray(np.load(path, mmap_mode='r'), float)\n",
|
||||
" single = image if n == 1 else single\n",
|
||||
" cnn = image if cnn is None else cnn + image\n",
|
||||
" return eta, single, cnn\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"images = {}\n",
|
||||
"for region, boxes in REGIONS.items():\n",
|
||||
" eta, single, cnn = published(region)\n",
|
||||
" images[region] = {}\n",
|
||||
" for key, box in boxes.items():\n",
|
||||
" images[region][key] = {\n",
|
||||
" 'native readout (25 um)': cut_grid(analog, box, factor=1),\n",
|
||||
" 'eta interpolation': np.asarray(cut_chip(eta, box), float),\n",
|
||||
" 'cluster CNN 1ph': cut_chip(single, box) if single is not None else None,\n",
|
||||
" 'cluster CNN <=3ph': cut_chip(cnn, box) if cnn is not None else None,\n",
|
||||
" 'GridBased 2-20 keV': cut_grid(flattened, box),\n",
|
||||
" }\n",
|
||||
" images[region]['roi_raw_grid'] = cut_grid(raw, boxes['roi'])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "43f9cd97",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1. The two regions"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "29d6aaff",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T09:23:43.852994Z",
|
||||
"iopub.status.busy": "2026-09-28T09:23:43.852857Z",
|
||||
"iopub.status.idle": "2026-09-28T09:23:45.025073Z",
|
||||
"shell.execute_reply": "2026-09-28T09:23:45.024813Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 2530x506 with 5 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAACc8AAAIPCAYAAACvu7RHAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AAEAAElEQVR4nOydd3hU1dbG32mZmilJJp0UAoSOVBGlgwVBULEXsF97uWKXol5FxSvqxV4QC1gQC2JFQFQQRZRe0/tM2mSSmcmU/f3Bt7Yzk4QEBEFdv+fJA3PmzDn71LX3Wu9aWyGEEGAYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmGYfxDKo90AhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhvmzYfEcwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAM84+DxXMMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzDMPw4WzzEMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzD/OFg8xzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMw/zjYPEcwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAM84+DxXMMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzDMPw4WzzEMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzD/OFg8xzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMw/zjYPEcwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAMwzAM84+DxXMMwzAMwzAMwzAMwxwxpk+fDoVCcbSbwTCHjYULF0KhUGD16tWHvI1Ro0YhKyvrsLXpz+BwHHdbzJ49GwqFAgUFBYd920eDgoICKBQKzJ49+2g35ZiBbQHDMAzDMAzDMAzDMMcqLJ5jGIZhGIZhGIZhGOagqKqqwl133YU+ffrAbDYjNjYWnTt3xplnnolXXnnlaDfvb8n8+fOxcOHCo7b/rKwsdOnS5ajt/0iiUCgi/rRaLbKzs3HVVVehpKTkaDcPdXV1mD179hERrTH/THbt2oUZM2Zg3LhxiI+Ph0KhwJVXXtnm+qNGjWrxnNDf8uXL/8SW/86QIUOgVqvbfUYHDBiAmJgYVFVV/UktYxiGYRiGYRiGYRjmr4b6aDeAYRiGYRiGYRiGYZi/DkVFRRgyZAicTiemTp2Kq666CjExMcjLy8NXX32F+fPn44orrpDrv/TSS3j++eePYov/HsyfPx9ZWVmYPn360W7K35JevXrhrrvuAgC4XC58++23eOWVV7BixQps3rwZ8fHxct1LLrkE559/PmJiYv6UttXV1WHOnDkA9ouYmGOfzMxMeDweqNXHput13bp1mDdvHrKzszF48GB88cUX7f4mISEBTz75ZIvl/fv3PxJNbJerrroKV199NRYuXIj77ruv1XU2bdqETZs24ayzzkJiYuKf3EKGYRiGYRiGYRiGYf4qHJseHIZhGIZhGIZhGIZhjknmzZuHyspKzJ8/HzfffHOL76OrAGk0Gmg0mj+recwhEAqF4PP5oNfrj3ZT/jR8Ph9UKpUUNyUnJ+Piiy+W31933XVITk7GU089hYULF+Lf//63/E6lUkGlUv3pbWYOD0IIeDweGAyGI7YPhUIBnU53xLb/R5k0aRJqampgs9lQUFCA7Ozsdn9jNBojnpGjzQUXXIDbbrsNr776Ku69995Wp4R9+eWXAeCAVfUYhmEYhmEYhmEYhmF42laGYRiGYRiGYRiGYTrM7t27AQBjx45t9fv09PSIz9OnT29V1FBZWYkbb7wRWVlZiImJQVJSEi6++GIUFBRErLdw4UIoFAqsXLkSDz/8MDp37gydTod+/frhs88+AwBs374dEydOhMVigdVqxfTp0+F2u//wPletWoX58+ejW7du0Gq16Ny5c6uVl9avX49JkyYhNTUVWq0WKSkpGDNmDD755JM2zyNRW1uLGTNmoGvXrtDr9bDZbOjTp48UaxUUFEChUKCwsBBr1qyJmC6R2r1hwwZcfvnlyM3NhdFohNFoxJAhQ/D666+32N/s2bOhUCiwfft23HHHHcjMzERMTAzeeeeddtvaEbxeL+bMmYPu3btDp9MhLi4OkyZNws8//xyx3vjx42G32yGEkMt++OEHKBQKxMbGwu/3y+WbN2+GQqHAY489FrGNVatW4bTTToPNZoNWq0WPHj3w6KOPIhgMRqw3atQoZGVlobCwEOeffz4SEhKg0+nane5x3LhxAIA9e/ZELKf7I3oa1fLyclxyySWIj4+H0WjE8OHD8e2337b5DABARUWF/I1er8fIkSOxcePGiH2RsGnOnDny2mdlZR2w7a1RWloKhUIRIQQEgKuvvhoKhQLXXHNNxPLbbrsNCoUC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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 2530x506 with 5 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def limits(img):\n",
|
||||
" # grey levels from the central 60 % of the image: in LowerLeft the unshadowed\n",
|
||||
" # strip at x > 222 is several times brighter than the star (and brighter\n",
|
||||
" # still for GridBased, which does not lose its photons to pile-up)\n",
|
||||
" ny, nx = img.shape\n",
|
||||
" centre = img[int(.2 * ny):int(.8 * ny), int(.2 * nx):int(.8 * nx)]\n",
|
||||
" centre = centre[np.isfinite(centre)]\n",
|
||||
" return np.percentile(centre, 0.5), np.percentile(centre, 99.5)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def show(region, key, title):\n",
|
||||
" box = REGIONS[region][key]\n",
|
||||
" panels = [(name, img) for name, img in images[region][key].items() if img is not None]\n",
|
||||
" fig, axes = plt.subplots(1, len(panels), figsize=(4.6 * len(panels), 4.6))\n",
|
||||
" for ax, (name, img) in zip(axes, panels):\n",
|
||||
" low, high = limits(img)\n",
|
||||
" ax.imshow(img, cmap='gray', extent=[box[0], box[1], box[2], box[3]], vmin=low, vmax=high)\n",
|
||||
" ax.set_title(name, fontsize=10)\n",
|
||||
" ax.set_xlabel('x [pixel, 25 um]'); ax.set_ylabel('y [pixel, 25 um]')\n",
|
||||
" fig.suptitle(f'Siemens star {region}, {title}, 15 keV')\n",
|
||||
" fig.tight_layout()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"for region in REGIONS:\n",
|
||||
" show(region, 'roi', 'whole region')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "b4daba25",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T09:23:45.028865Z",
|
||||
"iopub.status.busy": "2026-09-28T09:23:45.028776Z",
|
||||
"iopub.status.idle": "2026-09-28T09:23:46.061555Z",
|
||||
"shell.execute_reply": "2026-09-28T09:23:46.061121Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAACdcAAAHtCAYAAADxptVPAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AAEAAElEQVR4nOzdd3hTZf8/8Hd20jRNmu492CAoKIgoFhAcCIKKiqICKu6J4vwqoD7ugXuLgDw4cCOiiICoqPi4xYFsWrpn2rRNmvv3B7/P/TTdRYYPvl/XxXXR5OTk5OTk3Otzf26DUkqBiIiIiIiIiIiIiIiIiIiIiIiIiDTj/j4AIiIiIiIiIiIiIiIiIiIiIiIior8bBtcRERERERERERERERERERERERERNcHgOiIiIiIiIiIiIiIiIiIiIiIiIqImGFxHRERERERERERERERERERERERE1ASD64iIiIiIiIiIiIiIiIiIiIiIiIiaYHAdERERERERERERERERERERERERURMMriMiIiIiIiIiIiIiIiIiIiIiIiJqgsF1RERERERERERERERERERERERERE0wuI6IiIiIiIiIiIiIiIiIiIiIiIioCQbXERERERERERERERERERERERERETXB4DoiIiIiIiKiRqZMmQKDwbC/D4NonwqFQpg1axays7NhNpv5G9jLampqcOWVVyI9PR0mkwmZmZm7va9hw4b9pdf/3RgMBkyZMqVD265atQoGgwEvvfSSfmzLli0wGAyYNWtWp997f9z//8rx/h39nT5PZ66lA0FLvwciIiIiIiIi+usYXEdEREREREQHvMLCQtx4443o27cvoqKi4HK5kJ2djZNPPhkvvPDC/j68A9KcOXP26wB/ZmYmunbtut/ef28yGAwYOXLkHt3nvHnzMHv2bAwfPhwvvPACFixYAACYNWsW3n777T36XgTce++9eOyxx3DGGWfgpZdewpw5c9rcfn//nujAt2rVKsyaNQvl5eX7+1AOGPfccw/OOOMMdOvWDUajEWazudVtX3rpJRgMhhb/TZgwYR8e9X89+eSTMBgMuPvuu9vc7tFHH4XBYMDDDz+8j46MiIiIiIiIaN9qvUVPREREREREdADYtm0bBg0ahOLiYkyYMAHTpk2D1WrFpk2bsHz5csyZMwfnn3++3v65557D008/vR+P+MAwZ84c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gw/i448/xhdffIGIiAgAQFVVFY488kisX78ekyZNwpAhQ7Bx40Y8+eSTWLZsGT7//HP07t077D3ff/99PPnkk7jkkktwwQUXYNGiRZgxYwbsdjvmzp2LlJQU3Hrrrdi5cyceeughjB8/Hj///DOMxrbnp+bm5mLgwIEoLCzEtGnT0K9fP/zwww947rnnsGzZMqxbtw4JCQk45ZRT0LVr12a/j379+rW43478ngCguroaQ4cOxaGHHoo77rgDBQUFePjhh3H88cdj06ZNcLlcetupU6di/vz5GDduHCZNmgQAePPNN3HyySfjqaeewsUXX9zmZxVLlizBQw89hEsvvRTnn38+Pv74Y8yZMwc//vgjli9f3u45a8t3332HxYsXY+rUqTj77LPx1Vdf4aWXXsLXX3+NdevW6WugoxYuXIizzz4bRx55JGbOnInIyEjk5ubik08+wYYNG9CzZ8+w7Y877jh4PB7cdNNNqKmpwZw5czB27Fhs2LAh7L47a9YszJ49G8OHD8fMmTPhcDjw4YcfYtq0afjzzz9xzz336G2ffvppXHLJJejevTtmzpwJi8WChQsXthmc1pqO3OuBXYFP06ZNQ2ZmJmbMmIHIyEgsXrwYl19+OX744Qc8++yzAIBbbrkFXq8Xb731Fh5++GH9m5TrsqP3k8Y6en109LcDdO6e3ZLPPvsM48aNQ0pKCpYuXaqD69sr1/alcePG6UDiXr164YorrsDFF1+824HNjz32GK6++mqcdtppuq7Rme/zqKOOQq9evbB48WI89thjcLvdet81NTVYtGgRsrKyWp3AQERERERERHRAUEREREREREQHsM2bNyuPx6MAqISEBHX66aerBx98UH355ZcqFAo1237y5MmqaXN5/PjxKjo6Wm3cuDHs8U2bNqnIyEg1ZcoU/djcuXMVANWvXz9VW1urH//uu+8UAGUwGNSrr74atp9x48Ypi8Wiqqqq9uh7+nw+FRMTo4444gj92COPPKIAqC+//LLN89aS8vJyZTAY1MUXX9zuthkZGSonJ6fF53w+X7PHGhoa1NFHH608Ho+qr6/Xj8+cOVMBUEcffbQKBAIdPtaMjAzVpUuXNrd54YUXFAB1ySWXhD3++++/K5vNprp166YaGhqUUkqtW7dOAVD33Xef3i4nJ0eNGTNGRUdHq9tuu00/fuKJJ6ro6Gj92p07dyq73a7Gjx/f7Jq7//77FQC1atWqsP0CUDfffHOLxw1AHXPMMW1+tjlz5igA6s033wx7vL6+XvXv319lZWWFPZ6Tk6MyMjJafK/Jkye3+V67o7KyUh188MHK6XSqdevW6ceHDh2qDAaDWrt2bdj2s2fPVgDUHXfcoR+79dZbFQB1773Line truncated
|
||||
"text/plain": [
|
||||
"<Figure size 2530x506 with 5 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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aKxzS9aePXsCAPbt2xdwnNrHyduopqWl4dZbb0VYWBgsFgs6deqE7777rtY+AFQFb9E1JpMJXbp0wS+//BLwLAqUmDZtmvz2ZxrUUdt2hDXd88cff0S/fv3gdDphNBqRlJSEp59+GpWVldXue+zYMdx5552oV68e9Ho9YmJicNdddyEtLS3gvI0bN0KlUmHBggV455130LRpUxiNRjRu3BiLFi2S9xoyZIisx+TkZKSnpwf9jn/99ReGDBmCiIgI2W8fffRRFBYWynPomwghsHDhQlkHtW2NTOUGEHB+Td917969GDhwIGw2G0JCQtC3b18cOHCg2nmVlZV48cUX0aJFC5hMJoSGhqJnz5747rvvgnpPZV2+9dZbSEpKgtFoREJCAp566il4vd6A86kf1IRKpao1q+Vnn32G1q1bw2QyITo6GuPGjUNJSclplY8QQuC1115Dq1atZP0kJiZi+PDhyMjIqHaPuvqH8r5z585Fu3bt5BjYsWPHWrfYffXVV9GkSRO5RfPTTz9drb5OBY2je/fuxeTJkxEfHy/HoA8//LDGaz744AO0b98eISEhsFgs6NChAz766KOAcxISEuS4rWxjyjosKirCE088IcvvdDqRnJyMHTt21FreYNoHEFzfIfLz8zF+/HjUr18fBoMBERERGDp0aLXxsjZ++OEHuFwuXH755Thy5AiAquD7u+66C/Xr14fRaITL5UKbNm3wwgsvBHXPmjAYDDJw7nQpKioKkEX/lLfeegtarRY333wzKioq5DOC+Z5jxoyBEALz58+v8d7z5s0DUJWljmEYhmEYhmEYhmEuJngJGMMwDMMwDMMwDHPRkZiYCACYP38+XnjhhTPKcHLkyBF07NgRxcXFuOOOO9C4cWMcO3YMb731Fr755hv8/PPPiIuLC7jmf//7HyoqKjB27FhoNBrMnj0bAwcOxGeffYY77rgDN998M/r374+tW7di4cKFMBgMmDNnzj965qRJk1BYWIjRo0cjJCQEixYtwvjx4xEVFYUhQ4YAqAqU6dmzJ9xuN+677z5ERUUhKysLv/76K7Zu3Vrn9mk333wzNmzYgLvuugutWrVCRUUFDhw4gPXr1wMA3G43Fi9ejHHjxsHlcuGJJ56Q17rdbgDAsmXLsGvXLgwePBjx8fEoKCjAJ598glGjRiErKwuPPvpotecOHz4cOp0O999/PywWC5o0aXIaX7BmfD4f+vTpgw0bNqBfv364//77kZ6ejrfeegvXXHMN1qxZg27dugGoCkxbt24dfv/9d7Rq1QoAsH79eqjVahQXF2Pbtm3o1KmTPA4EBmy+9957uPPOO9GqVSs8/vjjsNvt2LJlC/73v//ht99+qxaUUlxcjE6dOqFdu3aYNm0aioqKEBIScsr32b9/PwAEbNlaGwUFBejUqRNSUlJw++23o02bNtizZw/69OmDhg0b1nhNSUkJOnXqhDZt2uDpp59GRkYGXnnlFVx//fVISUmB1WpF586d8corr2DcuHG44YYbMGjQIACos+y1sXjx4mrH/vzzT0yfPh2RkZHy2FdffYUBAwbAZrPhvvvuQ0REBFavXo3Jkyfjhx9+wKpVq6BWV60LPXbsGNq2bYvMzEyMGTMGLVq0wB9//IG5c+fiq6++wk8//YSIiIiAZ7755pvIysrCmDFjEBISgnfffRcjR46ETqfD//73P3Tq1AnPPPMM/vrrL7zxxhsYOXIkvv766zrf7/fff0fnzp3h8/kwduxYNGjQAN9//z1eeuklrFu3Dj/88APMZjPuvvtu9OzZE7feeis6deqEu+66CwDQsWPHGu+blJSExYsXVzv/ZI4dO4bOnTtjwIABeOGFF7Bv3z689tprGDBgAHbu3CnrzOv1ok+fPti0aROGDh2Ke+65B6WlpXj//ffRvXt3LF++HP369avzfQHg9ddfx9GjR3HPPffA6XRi2bJlmDJlClJSUmoNBgyWlStX4uWXX8a9996LO+64A+vWrcOsWbOwY8cOrF27Vr5PsDz33HP4v//7P/Tt2xd33nkn9Ho9Dh8+jK+++grp6ekB7SSY/kGMHj0aixYtwsCBAzF8+HAAwOeff44bbrgBb731Fu655x557uOPP44XXngBV155JZ5//nmUlZXhvffew4oVK067fkaOHAmVSoUHH3wQarUab775JoYPH44GDRqgQ4cO8rzJkyfj6aefRosWLfDkk08CAN5//30MHToUKSkpmDRpEoCq7blffvllbN68OaCvUrssLCzENddcg/3792PkyJFo2bIl8vLyMHfuXFx11VXYvHkzWrduHVDGYNtHsH0HqAr4uvrqq7F7924MHz4cHTt2xIEDB/Dmm2/iq6++wpYtW065xenSpUsxYsQIdOjQAcuWLYPdbofX60WvXr1w5MgRjB07FpdddhmKiorw999/49tvv8Vjjz122t/nn9CyZUsUFhZCrVajVatWmDhxIm6++eYzupcQAv/73//wwgsvYNy4cXjppZegUqlO63sOHjwYDz74IBYsWICpU6cG9L3Dhw9j7dq16NKlCxo1anRW3p9hGIZhGIZhGIZh/jULine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 2530x506 with 5 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"for region in REGIONS:\n",
|
||||
" show(region, 'zoom', 'zoom of the published notebooks')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cba943fe",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### GridBased 2–20 keV at full size\n",
|
||||
"\n",
|
||||
"The flattened reconstruction of each region at 2.5 µm, and the same photons\n",
|
||||
"before the sub-pixel flattening (the 25 µm pixel grid is visible there)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "76f70e13",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T09:23:46.065314Z",
|
||||
"iopub.status.busy": "2026-09-28T09:23:46.065072Z",
|
||||
"iopub.status.idle": "2026-09-28T09:23:46.886751Z",
|
||||
"shell.execute_reply": "2026-09-28T09:23:46.886518Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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P//zP/HsZz8bf/jDHyRR/MUvfoFXvvKVeNaznoUrr7wSJpMJu3fvxi233CLbajQaOOecc7B//3686U1vwuTkJP70pz/h05/+NO6///4+H9c3v/nN+MpXvoKXvexlOOecc3DHHXfgOc95DhqNxkM+h0QikQCwlng9mtv44x//CJvNhuOOO67vu9u3b4fVasWdd975kP5Gs9nEy1/+cvzyl7/Ej3/8YzzrWc8CsHYvfOELX8CrX/1qvPWtb0UymcTnPvc53HrrrbjrrruEwfS3f/u3+MhHPoI77rijL4G6/fbbsXfvXnzkIx95OId+RNizZw/OOOMM2Gw2vPvd74bb7ca1116L5z//+fje976HCy+8EAaDAc94xjNw0003ye/Nzs5iaWkJRqMRN910EzZs2AAAuPnmmxEMBuWezGazOP3009FsNvGmN70J8Xgct9xyCy677DIkEgl89rOf7dufr33ta6hWq3jTm94Et9t9yOdhPRzJ+f7sZz+Lb37zm7jhhhvwmc98BuFwGJOTkzj33HPxute9Dqeffjre9KY3AQAGBgYe0rm8/PLLceyxx+Lf/u3f8MEPfhBbtmw57Da+/OUvw2Qy4e/+7u8QCARw22234dOf/jSWlpYk0X7zm9+MxcVF/OpXvxIvawCIRCK47rrrDrnPD+XZBYDbbrsN3/ve9/DWt74Vr3/96/GlL30JF110EbZv347Nmzc/5G0+FuuBgoKCgoLCExkqf1jD4x0vqPxB5Q9PpvyB6PV6eN7znocTTjgBn/jEJ/Cb3/wGV199NfL5PK699lr53qc+9Sm8733vw0te8hK8+tWvRqVSwec//3mcccYZuPPOOzExMXHYnOTmm2/Gc57zHAwPD+NDH/oQer0evvCFL+Css87CTTfddFAzb7216ZZbbsFzn/tcHHvssbj88sths9lwww034MILL8R3vvMdvOQlL1n3GJm/fPKTn0QikcBnPvMZAGuNxvVQKpVwzTXX4BWveAVe+9rXotFo4Otf/zpe/OIX46c//SnOO+88ADhkTjQ5OYm3ve1tfedB//ce6nG8+93vht1uxwc+8AFks1l86lOfwt/+7d8eUSPwSHKtlZUVnHXWWeh0Onjve9+LYDCIr33ta/j5z3/+oNtXUHhSQ1NQUFA4AMFgUDv++OMP+rxSqWiZTEb+KxaL8rNrr71WA6CddtppWrvd7vu9G2+8UQOg3XjjjfLZiSeeqIXDYS2Xy8ln9957r2YymbQDl6axsTENwEH/nXzyyVoikej7bqPR0DqdTt9n+Xxei0aj2hve8Ab57F3vepfm9XoP+q4eV155peZwOLR777237/N/+7d/0wBoN998s6ZpmrZz504NgPa6172u73sf+MALine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1650x814 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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dx18Ph8+97nPHdXR+OMf/4i3vvWtWLhwIb74xS8in8/js5/9rJCqB6NUKmFmZgYAUCgUsGPHDtxyyy044YQTsHz5cnnf/v378R//8R945zvfiYULFyKZTOJf//Vf8aY3vQlbt26VQPGhhx7CpZdeis2bN+Pmm2+GyWRCT08PnnjiCfmsfD6Ps846C/39/bjqqquwYMECvPDCC7j11lvR3d2N++67T9579dVX46677sI73/lOnHXWWXjuuefw5je/Gfl8/mWPITE+Pg5gLvB6LT/j+eefF2dZjxNOOAFWqxXbtm17Wd9RKBTw7ne/Gw8//DAeeOABbN68GcDcXPj+97+PD3zgA/jwhz+MyclJfPe738WWLVuwfft2Uf28733vw0033YTnnnuuJoB69tln0dfXh5tuuumV3Poxobe3Fxs2bIDNZsPHP/5xOJ1O3HnnnXjLW96CX/7yl7j44othMBhw+umn47HHHpO/GxgYwOjoKIxGIx577DHMnz8fAPD444/D7/fLnJyZmcEpp5yCQqGAq666Ck1NTXjiiSfwqU99CuPj44c4p//2b/+GTCaDq666Ck6n84jrAQASiQTi8TgWLFjwkvd5xx134Oqrr8Ypp5yC6667DtPT0/jABz6A1tbWw77/F7/4BSKRCK655hrU1dXh29/+Nt7+9rdjaGgIfr8f73jHO9Dd3Y177rkH3/rWt2R+vZx+x0uXLsVPf/pTXH/99fB4PPjc5z531M84lrXd0NCA2267Df/v//0/vP3tb8c73vEOAMCCBQtQX19/1Gu+55578Fd/9Vc466yz8MUvfhHVahU/+tGPsHnzZjz22GOH9DJ/73vfi3A4jC9+8Yvo6+vDd7/7XVgsFvzsZz+T9xzrZ+7Zswdnn3023G43Pv/5z8NqteKOO+6A0+k85vFUUFBQUFB4I6Hihzmo+OHYoOIHFT+8kvhBj5/97GeIx+P48Ic/DIPBgH/+53/GOeecg2effRbLli0DcGxjebSYRNM0vOMd78Dvfvc7fPCDH8TJJ5+MJ598El/84hexZ88e/OIXv6i5pn379uGSSy7BlVdeiQ996ENob2+Hpmm45JJL8OCDD+LKK6/EypUr0d/fj9tuuw3btm3Dn/70pyO28rr66qsxb9483HjjjbjqqqtwxhlnHDU+uPfeexGNRnHllVciHA5j586d+OEPf4gXX3wRTz75JAAc9Tl8+9vfxt/+7d/WjAO/7+Xex8DAAC688EJcfvnleN/73od77rkHH//4x7Fs2TKcc845L/l8jyXW+tznPoebb74Z5557Li666CL09fXhggsugN/vP+I8VVA4rqApKCgoHAZ+v19bvXr1Ia+n02ktEonIv0QiIb+78847NQDLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1650x814 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"for region, boxes in REGIONS.items():\n",
|
||||
" box = boxes['roi']\n",
|
||||
" fig, axes = plt.subplots(1, 2, figsize=(15, 7.4))\n",
|
||||
" for ax, img, name in ((axes[0], images[region]['roi']['GridBased 2-20 keV'], 'flattened'),\n",
|
||||
" (axes[1], images[region]['roi_raw_grid'], 'before flattening')):\n",
|
||||
" low, high = limits(img)\n",
|
||||
" ax.imshow(img, cmap='gray', extent=[box[0], box[1], box[2], box[3]], vmin=low, vmax=high)\n",
|
||||
" ax.set_title(f'GridBased 2-20 keV, {region}, {name}', fontsize=11)\n",
|
||||
" ax.set_xlabel('x [pixel, 25 um]'); ax.set_ylabel('y [pixel, 25 um]')\n",
|
||||
" fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "318433ac",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2. Profiles and FRC\n",
|
||||
"\n",
|
||||
"A row through the zoom (normalised to its mean), and the one-image Fourier ring\n",
|
||||
"correlation as `SiementStar_LowerLeft.ipynb` computes it (`frc.one_frc` and\n",
|
||||
"`frc.frc_res` on the 50 × 50 px box x 162–212, y 140–190, no window; for\n",
|
||||
"LowerRight the same box around its star). The cutoffs are in that notebook's\n",
|
||||
"units, so they compare with its ML 2.041 / eta 2.053 for LowerLeft."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "6162c863",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T09:23:46.891035Z",
|
||||
"iopub.status.busy": "2026-09-28T09:23:46.890941Z",
|
||||
"iopub.status.idle": "2026-09-28T09:23:47.101421Z",
|
||||
"shell.execute_reply": "2026-09-28T09:23:47.101191Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAABfYAAAHCCAYAAACt2ZiFAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AAEAAElEQVR4nOzdd3gU5fbA8e9sT28EQgsggqCCiApYLt0uWFFUQPyBiqJw5Vqwgyh2bNfeQAT1YgHsAgJ6vSqiogIivZc00rfOvL8/ZndJSNtAQjZwPs/DQ3Z2yjszu8nMmfOeV1NKKYQQQgghhBBCCCGEEEII0ShYGroBQgghhBBCCCGEEEIIIYSInAT2hRBCCCGEEEIIIYQQQohGRAL7QgghhBBCCCGEEEIIIUQjIoF9IYQQQgghhBBCCCGEEKIRkcC+EEIIIYQQQgghhBBCCNGISGBfCCGEEEIIIYQQQgghhGhEJLAvhBBCCCGEEEIIIYQQQjQiEtgXQgghhBBCCCGEEEIIIRoRCewLIYQQQgghhBBCCCGEEI2IBPaFEEIIIYQQQgghhBBCiEZEAvtCCNFIbdq0iYsuuoj09HQ0TWPkyJEN3SQhhBBCCCGOWH379qVt27YHvPzmzZvRNI1JkybVWZuEEEIcviSwL4SICkuWLEHTNB566KGGbkqdmz59Opqm8c4779TpekeOHMnSpUu58847mTlzJjfccAMrVqxg0qRJbN68uU63JSL3999/c/vttzNw4EDS0tLQNI3Ro0dXOX8gEODxxx/n+OOPx+VykZKSwvnnn8/y5curXOa1117jhBNOICYmhvT0dK666iq2bNlSH7sjhBBCCFGlI+Eavuy/hIQETjnlFJ577jl0XW/oJrJkyRImTZpEfn5+QzfliLVs2TLGjx9P7969SUxMrPH74PV6ef755znppJNISUkhKSmJrl278sgjj1BcXFxh/kAgwGOPPcYxxxyD0+mkRYsW3HjjjeTm5tbnbgkhGgkJ7AshRCPk9Xr57rvvGD58OLfddhvDhg3j1FNPZcWKFUyePFkC+w3ohx9+4Mknn2Tjxo2ccsop1c6rlOLiiy/mzjvvJD09nSeeeIKJEyeyZs0azjjjDL777rsKy9x3331cf/31JCQk8MwzzzB+/HgWLFjAqaeeyvbt2+trt4QQQgghjkg33ngjM2fO5O233+a+++6jtLSU8ePHM3bs2Arzfv311/z999+HrG1Llixh8uTJEthvQJ9//jn//ve/yc7Opnv37jXOP3ToUMaNG0dmZiYPP/wwU6dOpU2bNtx9992ce+65Fea/9tprmThxIh07duTf//431157LW+//Ta9e/emqKioPnZJCNGI2Bq6AUIIcbgqKSkhLi6uXta9Z88elFKkpqbWy/qrU5/7dTgYNGgQeXl5pKSksHnzZtq1a1flvPPnz+fTTz/l7LPP5osvvkDTNABuuOEGOnXqxHXXXcdff/0Vnr527VoeeeQRunfvzpIlS7DZzD/j559/PieffDJ33303b7/9dv3vpBBCCCHEYWr/a93TTjuNYcOGhV/fdNNNdO7cmddee40pU6aQnp4efs/hcBzSttY3pRRut5vY2NiGbkrUuvHGG7ntttuIj49nyZIl9OvXr8p5169fz9y5c7nkkkv48MMPw9PHjh3LoEGD+PTTT1m1ahXHHXccAN988w3vvPMOgwcPZt68eeH5e/TowUUXXcQTTzzBgw8+WH87J4SIepKxL4RodNasWcPQoUNp1qwZTqeTo446ittuu43CwsLwPDt27EDTNP71r3+VW/b6669H0zRuuOGGctMnTJiApmns2bMnPM3n8/H444/TtWtXYmJiSExMZODAgXz77bflli1bC/PDDz+kR48exMbGcv7559d63zZs2MDIkSNp0aIFDoeDVq1acdNNN5GTkxOep2/fvrRp0waAyZMnh7sGt23blmuvvRaAfv36haeXrb2/detW1qxZg9/vr7Etoa7V06dP55VXXqFr1664XK5y2UmzZs2iZ8+exMfHExcXR69evXjvvffKrefhhx9G0zT+/PPP8DS/3098fDyapvHDDz+EpyulaNKkCeedd161bTv//POJiYlh7969Fd7buXMnNpuNoUOH1riP9SEtLY2UlJSI5v3mm28As6xSKHgPkJyczIUXXsjff//N999/H54+e/ZsdF1n3Lhx4aA+wIknnki/fv344IMPcLvdNW439LlYvHgxp59+OnFxcTRp0oRrr72W7Ozs8Hy6rtOnTx9cLhe//vprhbZbrVYuuuiiiPZVCCGEEEe2w+UaPj4+np49e2IYBhs2bCj3XlU19r/88kt69uxJTEwMTZs25brrriMvL6/acbK++OILevXqFV5mzJgxlJaWltvW5MmTAWjXrl342r9sff4NGzawZs2aavcnJFR6aOHChTzyyCN07NgRp9PJ448/DoBhGDz33HPhcpCJiYn079+fBQsWlFvPddddh81mK9eLYOfOneH27dq1Kzw9Pz8fq9XKTTfdVG3bjj/+eFq2bFlp+aOffvoJTdOYOHFiRPtZ15o1a0Z8fHxE8xYUFADQsmXLCu+1atUKoNxDlFDCzoQJE8rNe+GFF3L00UdHlNBT9nP+wQcf0L17d2JiYmjRogW33norJSUl4XmLi4vp1KkTaWlpbNu2rdx6ZsyYgaZp/POf/4xoX4UQh4Zk7AshGpUVK1bQu3dvdF3nxhtv5KijjuK///0vTz31FAsXLuR///sfsbGxtGzZkk6dOrFw4cJyyy9atAiLxVLp9OOPP55mzZoBZi3D8847j6VLl3LllVeGL6Tfeecd+vfvz9y5c7ngggvKrWPevHk888wzjBkzhuuuuw6lVK33rW/fvsTGxvJ///d/tGnThnXr1vHSSy+xaNEili1bRlJSEvfccw8XXXQRt956KxdffDGXXHIJAK1bt2b27Nm8+uqr3H333XTu3BmA9u3bh7cxYsQIli5dyqZNmyIe2OvZZ59lz549XH/99bRs2ZKEhAQA7r//fqZMmULXrl257777AHjnnXe48sor2bhxI3fffTcAAwcO5N5772XhwoV06dIFgB9//JGSkpLwuTj11FPDxyA3N5cBAwZU26YxY8bw+eefM3PmTMaNG1fuvbfeegtd17nuuutq3LeCgoKIHnIA2O12kpKSIpo3Ul6vF6DSLKjQtB9//JEzzjgDMG9cwMwc299pp53GokWL+PPPP+nRo0eN2/7tt9/44IMPuPbaaxk2bBg//fQT06dPZ9myZfz888/ExsZitVp599136datG5dffjm//voriYmJZGVlcfXVV9O6dWveeuutA95/IYQQQhwZDrdr+FBAPy0trcZ558+fz8UXX0zz5s2ZOHEiKSkpzJs3j3POOafKZb744gv+/e9/c8MNNzBy5EgWLVrEK6+8AsDLL78MwD333ENqaioff/wxTz/9NE2aNAGga9eu4fUMGDCALVu21Oq+5Pbbb8ftdnPNNdeQnp5O69atATMRZebMmZxxxhk88sgjFBUV8frrr3P22Wfz9ttvh3s1DBw4kNdff53Fixdz8cUXA+Z5CiWxLFy4kOHDhwOwePFiDMOo8dr/hhtuYNy4cXz22WcMHjy43Huvv/56jWNahezduzfisRFcLlfEAftIHXfccbRo0YLXX3+drl27MmDAAJRSfPXVV7z11luMGjWqXG/fn376CYvFQq9evSqs69RTT2XmzJlkZWXRtGnTGrf96aefMm3aNG666SZGjRrFwoULeeaZZ/jjjz9YsGABFouF+Ph4/vOf/9CzZ0+uuOIKvv32W2w2G3/99Rdjx47l5JNPDj/oEUJECSWEEFFg8eLFClBTpkypdr5//OMfStM09cMPP5SbPnny5ArLjx07Vmmapvbs2aOUUmrTpk0KUMOHD1eA2rhxo1JKqaysLKVpmho/fnx42WeeeUYB6qOPPiq3HZ/Pp0488UTVrl278LTQem02m1q1alWFNr/11lsKUDNnzqx237p166batWuncnNzy03/8ccflcViUZMmTaqwzQceeKDSbS1evLjSbfTp00cBatOmTdW2Ral95yQlJSV8DEPWrl2rLBaL6t69uyotLQ1PLy4uVscff7yyWq3hbQQCAZWUlKTOO++88HwPPPCASklJURdccIHq3bt3ePoTTzyhAPXbb79V2zZd11VmZqbq0qVLuemGYah27dqp9u3bK8MwatzH0PGI5F+fPn1qXN/+Qudp1KhRlb7/3HPPKaDcZy+0HyeeeKIC1C233BKefvzxxyug3DEPeeWVVxSgPvzwwxrbFdqnOXPmlJv++OOPV/o9/PLLL5WmaWrIkCFK13U1cOBAZbfb1Y8//ljjtoQQQghx+DoSruFfeukllZ2drbKystTvv/+urr/+egWoXr16VVimT58+qk2bNuHXgUBAZWZmqsTERLVz587wdF3X1YUXXqgAdc0111RoU0xMjNqwYUO5dZ999tnKbrer4uLi8LQHHnig2mv7Nm3aqEjDPqH97dChQ7ltKKXUokWLFKAuuOACFQgEwtOzsrJU06ZNVXJysioqKgpP0zRN3XTTTeH5rrnmGnXCCSeorl27qhEjRoSnjx07Vlkslgr3P/vLz89XsbGxatCgQeWmFxUVqfj4eNW/f/+I9jF0PCL5V/a8RCqS78Mvv/yiTjjhhHLbslgslS4THx+vmjZtWul67rrrLgWoX375pdo2hT5Tmqapn376qdx7Y8eOrfQ+NXRfcdttt6nS0lJ1/PHHq6SkpAqfSSFEw5NSPEKIRiM7O5vvvvuOs88+u0LWwm233UZcXFy5WoWhDIhQuZNFixZhtVqZPHkyVquVRYsWAWZJEaVUuUyRmTNn0rZtW/7xj3+Qk5MT/ldQUMDgwYPZtGkTa9euLdeG888/n2OPPfaA9m3lypWsWLGCoUOHYhhGuW22b9+eDh068NVXXx3QustasmQJSqmIs/XLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1540x462 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"fig, axes = plt.subplots(1, len(REGIONS), figsize=(7 * len(REGIONS), 4.2))\n",
|
||||
"for ax, region in zip(np.atleast_1d(axes), REGIONS):\n",
|
||||
" box = REGIONS[region]['zoom']\n",
|
||||
" for name, img in images[region]['zoom'].items():\n",
|
||||
" if img is None or name.startswith('native'):\n",
|
||||
" continue\n",
|
||||
" row = img[img.shape[0] // 2]\n",
|
||||
" ax.plot(box[0] + (np.arange(len(row)) + 0.5) / B, row / row.mean(), lw=1, label=name)\n",
|
||||
" ax.set_xlabel('x [pixel, 25 um]'); ax.set_ylabel('intensity / mean')\n",
|
||||
" ax.set_title(f'{region}: row y = {(box[2] + box[3]) / 2:.0f} px'); ax.grid(alpha=.3); ax.legend(fontsize=8)\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "81b5a618",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T09:23:47.102562Z",
|
||||
"iopub.status.busy": "2026-09-28T09:23:47.102478Z",
|
||||
"iopub.status.idle": "2026-09-28T09:23:48.132289Z",
|
||||
"shell.execute_reply": "2026-09-28T09:23:48.132064Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"DIPlib -- a quantitative image analysis library\n",
|
||||
"Version 3.5.1 (Jul 5 2024)\n",
|
||||
"For more information see https://diplib.org\n",
|
||||
"region reconstruction FRC cutoff: median range crossed\n",
|
||||
"LowerLeft eta interpolation 2.049 2.033-2.053 5/10\n",
|
||||
"LowerLeft cluster CNN 1ph 2.033 2.024-2.045 4/10\n",
|
||||
"LowerLeft cluster CNN <=3ph 2.062 2.062-2.062 1/10\n",
|
||||
"LowerLeft GridBased 2-20 keV 2.169 2.151-2.342 10/10\n",
|
||||
"LowerRight eta interpolation nan nan-nan 0/10\n",
|
||||
"LowerRight cluster CNN 1ph nan nan-nan 0/10\n",
|
||||
"LowerRight cluster CNN <=3ph nan nan-nan 0/10\n",
|
||||
"LowerRight GridBased 2-20 keV nan nan-nan 0/10\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAABfgAAAHCCAYAAACzEKg2AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AAEAAElEQVR4nOzdd3wURRvA8d9eyV16TwgthN5771V6F0SUoiCKXVRQsVAUGxaK2F6QIiqCiCJK70WagPSahARCeq9X5v3jzElIaNLh+fK5T8js7Ozs7iWZmZt5VlNKKYQQQgghhBBCCCGEEEIIcUfR3eoKCCGEEEIIIYQQQgghhBDi6skAvxBCCCGEEEIIIYQQQghxB5IBfiGEEEIIIYQQQgghhBDiDiQD/EIIIYQQQgghhBBCCCHEHUgG+IUQQgghhBBCCCGEEEKIO5AM8AshhBBCCCGEEEIIIYQQdyAZ4BdCCCGEEEIIIYQQQggh7kAywC+EEEIIIYQQQgghhBBC3IFkgF8IIYQQQgghhBBCCCGEuAPJAL8QQgghhBBCCCGEEEIIcQeSAX4hxB0tPDycXr16ERgYiKZpDB069FZX6aYrU6YMrVu3vtXVuKQJEyYQGBhIenr6ra6KENckIiICk8nEDz/8cKurIoQQQtzWWrduTZkyZf7z/hEREWiaxrhx465bne4md0Lf59FHH6VatWrY7fZbXRUhrsnWrVvR6XRs27btVldFiCLJAL8Qt5H169ejaRpvv/32ra7KdTd79mw0TePbb7+9ruUOHTqUDRs2MGbMGObNm8fjjz/O3r17GTduHBEREddc/rhx49A07aKv6Oho4N8OyPkvs9lMxYoVefHFF0lOTi6y/LS0NN5//32aNWuGn58fRqOR4OBgOnXqxNdff01ubu41n8OtdvbsWT744ANeffVVPD09nekxMTG8/vrrdOnShZCQEDRNo3379pctb9GiRbRp0wYfHx9cXV0pX758oc7N8ePHGTduHM2aNaNYsWK4u7tTtWpVnn32WWJiYq7pfJKTk5k2bRpdunQhNDQUs9lMWFgY999/P3v27CmUPyMjgwkTJtCrVy9CQ0PRNI3y5csXWbZSivnz5/PQQw9RqVIl3N3dCQkJoU2bNvz8888opa6p7v/1muebPn16off+hRYvXkzjxo1xd3fH19eX7t278/fff19TvQEWLlzIsGHDqFOnDi4uLmiaxubNmy+aPzw8nCFDhhASEoLJZKJMmTK8+OKLpKWlFZk/MTGRkSNHUrx4cUwmE5UqVeL999/HarUWyFemTBmGDRvGmDFjyM7OvubzEkIIcfe4F9ry5788PT1p0KABU6dOxWaz3eoqsn79esaNG0dKSso1lzV06NCLtv8NBkOBY1643c3NjRo1ajBhwoSLthXi4uJ4/fXXqVevHj4+Pri4uFCiRAl69erFggUL7ooB8T179jBnzhwmTpyITvfv0NPSpUsZPnw41apVw9PTk8DAQJo0acKsWbMKtbvy2e12vvrqKxo3boynpyceHh5UrVqVV155pUC+EydO8PDDD1OlShVnX6FixYqMGDGCkydPXtP52Gw2Ro4cSf369QkMDMRkMlG6dGl69OjBxo0bC+W/2nb3p59+Stu2bSlevDhms5mgoCCaNWvG3Llzr/nn6+jRo7z88su0b98ef39/NE1j+PDhV7z/Sy+9VOi9f6Gvv/6aWrVq4erqSmBgIAMHDiQyMvKa6g3w1VdfMWjQIKpVq4bBYLhkPwRg37599OnTh4CAAGebfuLEiRftV0dGRjJw4EACAwNxdXWlVq1afP3114XyNW3alE6dOvH8889fc59MiBvh4j+dQghxm8vNzWXTpk08/fTTvPTSS8702bNnM378+GueNXS+N954g4oVKxZK9/PzK/B969atGTZsGABJSUksX76cjz/+mFWrVrFr1y5cXFyceffs2UOPHj04c+YMnTt3ZuzYsfj5+REXF8eaNWt4/PHH2blzJ1999dV1OYdb5YMPPkDTNB5//PEC6UePHuWdd96hRIkSNGjQgKVLl162rKeeeorPP/+c7t27M3HiRFxdXYmKimLr1q0F8s2cOZOpU6fStWtX+vXrh5ubG3/++SczZsxg/vz5bNmyhcqVK/+n89m+fTvPPfccrVq1YsSIERQrVozjx4/zxRdf8PPPPzN//nwGDBjgzJ+QkMBbb71FUFAQderUISkp6aJl5+bm8vDDD1O1alV69epFxYoVSUhIYObMmfTp04eRI0cyY8aM/1Rv+G/XPN/p06d59dVX8fDwICMjo8g8M2fOZPjw4VSvXp3333+f3Nxcpk+fTrNmzdi8eTO1atX6z3X/7LPP+PPPP6lRowaVK1dm//79F8179OhRmjZtSnp6Oo8//jjVq1fnwIEDTJs2jQ0bNrBp0yZcXV2d+dPT02nZsiVHjx7lySefpGbNmmzatIlXXnmFAwcOMG/evALljxo1is8//5xvvvmGJ5988j+fkxBCCHGnGTlyJE2bNkUpRUxMDHPmzOG5557j0KFDfPHFFwXyrly58qYOhK1fv57x48czdOhQfHx8rkuZU6dOxdfXt0Da+YPV+e6//3569uwJQHx8PD/++CNvvfUWW7duZfny5QXyrlq1igceeID09HT69OnD4MGD8fT05MyZMyxfvpwBAwZw8uRJXnvttetyDrfK+PHjKVOmDL179y6Q/thjj+Hq6krPnj2pVq0aaWlp/PDDDwwbNozFixezdOlSNE1z5rdarfTt25fff/+dBx54wPnhS0RERKEJXdHR0Zw5c4ZevXpRokQJTCYTx44dY9asWfzwww9s2bKFGjVq/KfzsVqtbN++naZNm/LQQw/h7e3N2bNn+fbbb2nVqhWzZs3ikUcecea/2nb3jh07KFmyJJ06dSIgIIC0tDR+++03hgwZwtq1a5k9e/Z/qjfAtm3bmDx5MmFhYTRo0IAVK1Zc8b67du3i008/xcPD46IfWL3xxhu8/fbbNGvWjE8//ZT4+HimTJnC+vXrnef1X02aNImEhARq165NmTJlLvlBzebNm2nfvj1Go5GnnnqKsLAwtm3bxltvvcX27dsLvbeio6Np3LgxqampPP/884SFhbF06VJGjBjB6dOnmThxYoHyR40aRYcOHfjjjz/o0qXLfz4nIW4IJYS4baxbt04BauLEibe6KtdNRkaGUkqpb775RgFq3rx5163syMhIBai33nqrQHr+sdatW3fNx3jrrbcUoDZt2nTJfOHh4QpQw4YNK7StZ8+eClCLFi1ypsXGxqqQkBDl7u6u1qxZU2SZe/fuVZMnT75sHUNDQ1WrVq0um+9WyMjIUN7e3uqRRx4ptC0tLU3FxsY6vwdUu3btLlrW3LlzFaC++uqryx53586dKikpqVD6l19+qQDVr1+/KzyDwsLDw9XRo0cLpe/fv18ZjUZVrFgxZbPZnOk5OTnq9OnTzu9DQ0NVuXLliizbYrGo1atXF0rPyMhQFSpUUIA6ePDgf6771V7z83Xq1EnVq1dPPfzwwwpQUVFRBbYnJSUpLy8vVbJkSZWamupMj4qKUp6enqpFixb/ud5KKRUREaHy8vKUUpf/uezVq5cC1HfffVcg/bvvvlOAeueddwqkv/HGGwpQH330UYH0559/XgFF/ow2bdpUVa9e/VpOSQghxF3mXmzLp6enq5IlSyqdTqfi4uKu67Hz29cXtvUvJr99EB4efs3HHjJkSJHtnQtd7J5brVZVr149Bahdu3Y50w8fPqzc3d1VsWLF1N69e4ssc+3atWrmzJmXrSOghgwZcvmTuQUiIiKUXq9X48ePL7Rt1apVym63F0izWq2qefPmClDLli0rsG3ChAlKp9Op5cuX/+f6/Pnnnwoosk9yrdLS0lRgYKAKCwsrlP5f293n69y5swJUZGTkf65jQkKCs290qX7rhfLy8lSNGjVUr169VKtWrZRery+U5+jRo0qv16u6desqi8XiTP/rr7+UTqdTgwYN+s/1VkqpU6dOOftWl/u5rF27ttI0TW3evLlA+qRJkxSg5s+fXyB90KBBClA//fRTgfTevXsrvV6vjh07ViDdZrOpkiVLqq5du17TOQlxI0iIHiHuUEeOHGHAgAEEBwdjMpkoW7YsL730UoHwE2fOnEHTNF588cUC+44YMaLIGdWjRo1C0zRiY2OdaXl5eXzwwQfUrFkTV1dXvLy8aN++faFliOfHyPzpp59o2LAhbm5udO3a9arP7eTJkwwdOpTixYvj4uJCyZIlefLJJ0lISHDmad26NaGhoYBjdkj+ktgyZco4Z060adPGmX4r41PmL8U8fvy4M+3DDz8kJiaG9957j7Zt2xa5X61atQrdu0vZt28f9913H56ennh7e9O3b1/Cw8ML5cvJyWH8+PFUrlwZs9mMn58f3bt3Z9euXc48Z8+eJSgoiPLlyxcKaZIftujTTz+9bJ3++OMPUlNTi3wfeHp6EhQUdMXnN3HiRGrVqsVjjz0GOGZdX2z5cv369QvNtgKcM+uvJWRMmTJlilzNUb16dapXr865c+eIi4tzpptMJkqVKnVFZRsMBtq1a1co3d3dnW7dugHXVverveb55s6dy6pVq/j666/R6/VF5vnll19IS0tj+PDheHl5OdNLlixJ//792bRp0zWFzQoNDcVoNF5R3rVr1+Lq6lpgJQXAAw88gNlsZtasWQXS586di6urKyNHjiyQnv/zN3fu3ELH6NKlCwcOHODAgQNXcxpCCCEEcPe05T08PGjUqBF2u73QzNqLraZdvnw5jRo1wtXVlaCgIB577DGSkpIu2Wb/448/aNy4sXOfJ554gqysrALHGj9+PABhYWHOPsCtit+v1+udz8g6vw/wxhtvkJmZ6QxnUpQ2bdrw6KOPXvGx1q1bR7NmzXB3dycgIIBHHnmE+Pj4QvlSUlIYNWoUYWFhmEwmgoODefDBBwvUb//+/bi5udG0adNLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1540x462 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# one_frc splits the counts binomially with its own (unseeded) generator, so one\n",
|
||||
"# call is one draw: repeat it and quote the median and the range\n",
|
||||
"N_REPEAT = 10\n",
|
||||
"frc_results = {}\n",
|
||||
"try:\n",
|
||||
" import frc\n",
|
||||
" fig, axes = plt.subplots(1, len(REGIONS), figsize=(7 * len(REGIONS), 4.2))\n",
|
||||
" for ax, region in zip(np.atleast_1d(axes), REGIONS):\n",
|
||||
" frc_results[region] = {}\n",
|
||||
" for name, img in images[region]['frc'].items():\n",
|
||||
" if img is None or name.startswith('native'):\n",
|
||||
" continue\n",
|
||||
" square = frc.util.square_image(np.array(img, float), add_padding=False)\n",
|
||||
" size = square.shape[0]\n",
|
||||
" values, first = [], None\n",
|
||||
" for _ in range(N_REPEAT):\n",
|
||||
" curve = frc.one_frc(square)\n",
|
||||
" xs = np.arange(len(curve)) / size\n",
|
||||
" first = curve if first is None else first\n",
|
||||
" try:\n",
|
||||
" values.append(float(frc.frc_res(xs, curve, size)[0]))\n",
|
||||
" except Exception: # the curve never crosses 1/7\n",
|
||||
" values.append(np.nan)\n",
|
||||
" values = np.array(values)\n",
|
||||
" found = np.isfinite(values)\n",
|
||||
" frc_results[region][name] = dict(\n",
|
||||
" median=float(np.median(values[found])) if found.any() else np.nan,\n",
|
||||
" low=float(values[found].min()) if found.any() else np.nan,\n",
|
||||
" high=float(values[found].max()) if found.any() else np.nan,\n",
|
||||
" crossings=int(found.sum()), repeats=N_REPEAT)\n",
|
||||
" r = frc_results[region][name]\n",
|
||||
" ax.plot(np.arange(len(first)) / size, first, lw=1,\n",
|
||||
" label=f\"{name}: {r['median']:.3f} ({r['crossings']}/{N_REPEAT} crossed)\")\n",
|
||||
" ax.axhline(1 / 7, color='k', lw=.6, ls=':')\n",
|
||||
" ax.set_xlabel('spatial frequency (1/pixels)'); ax.set_ylabel('FRC')\n",
|
||||
" ax.set_title(f'{region}, FRC box {REGIONS[region][\"frc\"]}'); ax.grid(alpha=.3); ax.legend(fontsize=8)\n",
|
||||
" fig.tight_layout()\n",
|
||||
" print(f\"{'region':11s} {'reconstruction':20s} {'FRC cutoff: median':>18s} {'range':>15s} {'crossed':>8s}\")\n",
|
||||
" for region, values in frc_results.items():\n",
|
||||
" for name, r in values.items():\n",
|
||||
" print(f\"{region:11s} {name:20s} {r['median']:18.3f} {r['low']:7.3f}-{r['high']:.3f} \"\n",
|
||||
" f\"{r['crossings']:5d}/{r['repeats']}\")\n",
|
||||
"except Exception as error:\n",
|
||||
" print('FRC skipped:', repr(error))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "533a651d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3. Photon statistics\n",
|
||||
"\n",
|
||||
"Photons in each whole region. The cluster chains keep only clusters that fall in\n",
|
||||
"the 1/2/3-photon energy windows; at this occupancy the rest is lost to pile-up\n",
|
||||
"(`SiementStar_LowerLeft.ipynb`: 45 % of the photons are in single-photon\n",
|
||||
"clusters)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "47cb5a91",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T09:23:48.133530Z",
|
||||
"iopub.status.busy": "2026-09-28T09:23:48.133348Z",
|
||||
"iopub.status.idle": "2026-09-28T09:23:48.148052Z",
|
||||
"shell.execute_reply": "2026-09-28T09:23:48.147815Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"region eta (1ph) CNN 1ph CNN <=3ph GridBased photons per frame: GridBased / CNN <=3ph\n",
|
||||
"LowerLeft 1.4060e+09 1.4060e+09 1.6677e+09 1.8519e+09 185.2 / 83.4 = 2.22\n",
|
||||
"LowerRight 2.7039e+09 2.7039e+09 4.4703e+09 6.5713e+09 657.1 / 223.5 = 2.94\n",
|
||||
"(GridBased over 10,000,000 frames; the cluster chains used all 20 M)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"counts = {}\n",
|
||||
"CLUSTER_FRAMES = 20e6 # the cluster chains used the whole run\n",
|
||||
"print(f\"{'region':11s} {'eta (1ph)':>12s} {'CNN 1ph':>12s} {'CNN <=3ph':>12s} {'GridBased':>12s} \"\n",
|
||||
" f\"photons per frame: GridBased / CNN <=3ph\")\n",
|
||||
"for region in REGIONS:\n",
|
||||
" c = {name: float(np.nansum(img)) for name, img in images[region]['roi'].items()\n",
|
||||
" if img is not None and not name.startswith('native')}\n",
|
||||
" counts[region] = c\n",
|
||||
" cnn = c.get('cluster CNN <=3ph', np.nan)\n",
|
||||
" print(f\"{region:11s} {c['eta interpolation']:12.4e} {c.get('cluster CNN 1ph', np.nan):12.4e} {cnn:12.4e} {c['GridBased 2-20 keV']:12.4e} \"\n",
|
||||
" f\"{c['GridBased 2-20 keV'] / frames.sum():8.1f} / {cnn / CLUSTER_FRAMES:6.1f} = \"\n",
|
||||
" f\"{(c['GridBased 2-20 keV'] / frames.sum()) / (cnn / CLUSTER_FRAMES):.2f}\")\n",
|
||||
"print(f'(GridBased over {frames.sum():,.0f} frames; the cluster chains used all 20 M)')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b2edee48",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4. Energy spectrum from the energy head"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "75e762b8",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T09:23:48.149351Z",
|
||||
"iopub.status.busy": "2026-09-28T09:23:48.149259Z",
|
||||
"iopub.status.idle": "2026-09-28T09:23:48.409693Z",
|
||||
"shell.execute_reply": "2026-09-28T09:23:48.409471Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"15 keV line at 15.022 keV, core sigma 0.514 keV; below 13.5 keV 11.38 %, 13.5-16.5 keV 83.31 %, above 16.5 keV 5.31 %\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAy0AAAHCCAYAAADinSZ4AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAABDrAAAQ6wFQlOh8AAC5vklEQVR4nOzdd1xTV/8H8E8Ie6+w9xIQBfcGVKw8jrqtintU2zpaLdW2+rQ+HU9bW1vttK2jrda6rQO3uPdeKDIFRSGEvYR77+8PH/KTggoh4SaH7/v14tWS3Nz7Jd+cmJNzzvdIBEEQQAghhBBCCCFaSk/sAAghhBBCCCHkeajTQgghhBBCCNFq1GkhhBBCCCGEaDXqtBBCCCGEEEK0GnVaCCGEEEIIIVqNOi2EEEIIIYQQrUadFkIIIYQQQohWo04LIYQQQgghRKtRp4UQQgghhBCi1ajTQgghhBBCCNFq1GkhRAtNnDgREolE7DCIBhw5cgQSiQRr1qxp0uumpaVBIpHgww8/bNLrqsuHH34IiUSCtLQ0sUPROpGRkfDy8qr38RKJBBMnTtRYPGLz8vJCZGSk2GFoXEPzToiuo04LIU0kOzsbCxYsQKtWrWBpaQkLCwv4+PhgyJAhWLlypdjhMembb75p8s6BmNLS0vDhhx/iypUrYodCnkMul2Px4sXo1KkTbG1tYWBgADs7O3Tr1g0ffvgh0tPTmzwmiURS40dPTw+Ojo7o1q0bVq5cCZ7nmzwmTcvLy8O3336Lfv36wdPTE8bGxvD29sbw4cNx+fLlep9HEASsW7cOMTExaNGiBczMzODs7IyePXti27ZtEAShzscdO3YMvXr1Uv570KtXLxw7dkxdf16DVFVVwcXFBTY2NigrK3vmcZWVlXBycoJMJsPjx4+bMEJCqNNCSJO4d+8eWrdujS+//BItW7bExx9/jCVLlmD48OFIS0vDN998U+P4X3755bn/cJD6aY6dlsWLFzPZaVm4cCHKysrg6ekpdiiNcvjwYQQGBuLjjz+Gm5sbFi5ciJ9//hmLFi2Cj48Pvv76a/j7+zfoA+H+/ftx586dRsfWsmVL/PHHH/jjjz+wevVqvPnmm1AoFJg6dSrefvvtRp9f25w9exZz5sxBWVkZXn31VXz//fd45ZVXcPDgQbRv3x5//fVXvc5TUVGBsWPH4sqVKxg8eDCWL1+ON998E/fv38fQoUPxxhtv1HrMvn370Lt3b6SkpODf//43/vvf/0Iul6N3797Yt2+fuv/UF9LX18ekSZOQn5+PLVu2PPO4Xbt24dGjRxg/fjwMDQ2bMEJCAAiEEI2bNWuWAED45ptv6rw/IyOjiSNqHjw9PYWIiAiNnJvjOKG0tLTBj4uPjxcACKtXr1Z7TM87d2pqqgBA+OCDD9R+3fLycqGyslLt52XN7du3BXNzc8HZ2Vm4evVqnccUFRUJ8+fPFyoqKp57LlVff4IgCACECRMm1Lqtd+/etY7Nzc0VDAwMBCsrK5WuJYb6tvvU1FThzp07tW6/fv26YGBgIDg5OQkcx73wPJWVlcLBgwdr3V5cXCz4+/sLAISbN28qb6+qqhK8vLwEMzMzIT09XXl7YWGh4OHhIXh5eQlVVVUvvG5ERITg6en5wuPqKzk5WZBIJEJkZOQzj+nXr58AQLh165barktIfdFICyFNIDExEQDQu3fvOu93c3Or8fuz1rQ8evQIs2bNgpeXFwwNDeHo6IixY8fWmue/Zs0aSCQSHDp0CJ9++il8fHxgbGyM0NBQ7NmzBwBw69YtDBgwAFZWVrC2tsbEiRNRXFzc6GvGx8fjm2++QUBAAIyMjJTfHv/TmTNnMHDgQLi4uMDIyAjOzs7o1asXdu7c+cznsVpeXh5iY2Ph7+8PExMT2NjYoFWrVpg3bx6A/1+/kZ6ejqNHj9aY9lId97lz5zB58mTldA4zMzN07NgRv/32W63rVa+nuHXrFt555x14enrC0NAQGzZseGGsz/Pjjz8iKCgIxsbG8PLywn/+8x9UVVXVOu727dsYNWoUHB0dlc/p22+/jcLCwhox9uzZEwAwadIk5d9b19z+PXv2oHPnzjAxMYGDgwNmzJiB0tLSesVcPY8+PT0do0aNgr29PYyNjZGZmQkAKCoqwvvvv48WLVrAyMgItra2GDx4MK5du1brXIWFhZg5cyacnJxgYmKCdu3aYdu2bXWuX3nWmpb79+9j6tSpcHV1haGhIdzc3PDqq68iKyurxnFPryX6448/0Lp1axgbG8PV1RXvv/8+OI6rcXxCQgJGjx4Nd3d3GBkZwcHBAd26dcPq1avr9TzVZdGiRSguLsaqVavQunXrOo8xNzfHZ599VuNb7Be9/p61tuHAgQPKPMtkMkyePBlyubxBMVtbW8PY2LjWt+q3b9/GG2+8gZCQEFhZWcHExAStWrXC0qVLa00lq6iowEcffYTg4GCYmZnB0tISgYGBmDJlCioqKmoce/nyZQwfPhwODg4wNDSEj48PFixYUOfr8+LFi4iKioKZmRlsbGwwbNiwBq158vLyQkBAQK3bQ0JCEBISgocPHyI7O/uF59HX16/zvd3MzAwDBgwAgBqv/+PHjyMtLQ0jRoyAh4eH8nYLCwtMmzYNaWlpOH78eL3/jqcVFRWhb9++MDIywvr165W31+d59fHxQa9evXD06FEkJyfXOvf9+/exb98+dOvWDUFBQSrFR0hj6IsdACHNga+vLwBg9erV+Pzzz6Gv3/Cml5GRga5du6K4uBhTpkxBQEAA7t+/jx9//BH79+/HhQsXavwDCADvvvsuKioq8Nprr0EqlWLZsmUYNGgQNm/ejClTpmDkyJEYOHAgTp8+jd9++w1GRkZYsWJFo6753nvvobCwEJMmTYK5uTl+//13zJ07F87Ozhg1ahSAJ524qKgoyGQyvPHGG3B2dkZOTg4uXbqE06dPY+DAgc99LkaOHIn4+Hi8+uqraNOmDSoqKpCcnIxDhw4BAGQyGf744w+89dZbsLe3x/vvv698rEwmAwBs27YNN27cwPDhw+Hp6YmCggJs3LgREydORE5OTp3TYWJiYmBgYICZM2fCzMwMLVq0aEAGa/ruu++QmZmJGTNmwNbWFtu2bcMHH3yAlJSUGlParly5gvDwcHAch9deew0+Pj44ceIEvvrqKxw8eBCnTp2Cqakphg4disrKSnz66ad49dVX0aNHDwCAo6Njjevu2bMH3333HaZPn46JEyfi0KFDypz/9NNP9Yq9uLgYPXr0QMeOHbF48WIUFRXB3NwchYWF6N69O5KSkjBhwgSEhoYiLy8Pv/zyC7p06YLjx4+jbdu2AJ7MoY+Ojsbp06cxYsQIREZGIiMjAxMnTqzzg2Rd7t+/jw4dOiA7OxvTpk1D69atcfXqVfzyyy/Yu3cvzp8/X+vvX7FihbKjI5PJsHXrVnz66aewsLDAggULAAC5ubno2bMneJ7H9OnT4e3tjby8PFy/fh1Hjx7FpEmT6hXf0yoqKrBz5064u7sjOjq6wY8HGvb62717NwYNGgSZTIb58+fDxsYG27Zte+61KysrlZ0ajuPw4MEDLF++HEVFRYiNja1x7JEjRxAfH48BAwbA29sb5eXliIuLw7x585CSkoLvvvtOeezMmTPx66+/IiYmBrNnzwYApKamYufOnSgrK4ORkREAYO/evRg8eDDc3d0xa9YsODo64urVq1i6dClOnjyJ+Ph45XvnpUuXEB4eDqlUitmzZ8PNzQ379+9HZGQkSkpKVHp+q/E8j4cPH8LQ0BDW1taNOtf9+/cBAA4ODsrbzp49CwDo2rVrreOrbzt37lyDiwk8ePAA/fv3R1paGvbv34+IiAgADXtep02bhkOHDmHVqlX45JNPapx/9erV4DgOU6dObVBchKiN2EM9hDQHqampgrW1tQBAcHR0FEaOHCl89dVXwpkzZwSe52sdP2HCBOGfzXPw4MGCjY2NkJycXOP2lJQUwdzcXJg4caLyttWrVwsAhNatWwvl5eXK2y9fviwAECQSibBhw4Ya5xk0aJBgYGAgFBUVqfWaxcXFgp2dndClSxflbcuWLRMACGfOnHnu81aX/Px8QSKRCDNmzHjhsc+bJlJcXFzrNo7jhPDwcMHa2lp4/Pix8vYPPvhAACCEh4c3ehpU9RQuU1NTIS0trca1Bw4cKAAQjh8/rry9R48egkQiEU6fPl3jPIsXLxYACB999FGtcz9vepiJiUmtfPbt21cwMDCo8zn5p4iICAGA8N5779W678033xQMDAxq5TUvL09wc3OrMe3k559/FgAIsbGxNY49f/68IJFIBABCamqq8vbqHDx927hx4wQAtV7Lv/32mwBAmDJlivK26ufGyclJUCgUyts5jhOCgoIEZ2dn5W1///23AED466+/Xvh81Nf169cFAMLLL79c676KigohJyenxs/TbehFr79/ThPiOE7w8vISzM3NhXv37ilvr6qqUk7vqWt6WF0/xsbGwrJly2pd81mvlZiYGEEqlQpZWVnK22xsbITo6OhnPjeCIAhlZWWCk5OT0LFjxxp/uyAIwqZNmwQAwpo1a5S39ejRQ9DT0xMuXrxY49jp06cLABo1LXT58uV1PkcNdfHiRUFfX1/w8/Or8X4yc+ZMAYAQFxdX6zF37twRAAizZs164fmfzvv169cFd3d3wcPDo8ZUtIY+rxUVFYKdnZ3g4uJSY4oaz/OCj4+PYGlpKZSUlNT7OSBEnWh6GCFNwMvLC1evXsXs2bNhamqKjRs3Yt68eejcuTMCAgKUIwTPUlBQgB07dqBfv36wtLSEXC5X/lhYWKBz5851Lt6cOXOm8ltMAAgLC4OlpSWcnZ0xcuTIGsdGRESgsrJSOb1CXdc0MzNDly5dlFPkACi/vdy+fXuDCw6YmJjAyMgIZ8+eRUpKSoMe+zQzMzPl/5eVlSE3NxcKhQJ9+/ZFfn5+nQub33rrLZVGyeoLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 825x462 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def gauss(x, a, mu, sig):\n",
|
||||
" return a * np.exp(-0.5 * ((x - mu) / sig)**2)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"total = spectrum.sum()\n",
|
||||
"near = np.abs(spectrum_centres - 15) < 2\n",
|
||||
"peak = spectrum_centres[near][np.argmax(spectrum[near])]\n",
|
||||
"window = np.abs(spectrum_centres - peak) < 0.8\n",
|
||||
"try:\n",
|
||||
" (a, mu, sig), _ = curve_fit(gauss, spectrum_centres[window], spectrum[window],\n",
|
||||
" p0=(spectrum[window].max(), peak, 0.3), maxfev=20000)\n",
|
||||
"except Exception:\n",
|
||||
" if spectrum[window].sum() > 0:\n",
|
||||
" mu = np.average(spectrum_centres[window], weights=spectrum[window])\n",
|
||||
" sig = np.sqrt(np.average((spectrum_centres[window] - mu)**2, weights=spectrum[window]))\n",
|
||||
" else:\n",
|
||||
" mu = sig = np.nan\n",
|
||||
"fractions = dict(below=spectrum[spectrum_centres < 13.5].sum() / total,\n",
|
||||
" line=spectrum[(spectrum_centres >= 13.5) & (spectrum_centres <= 16.5)].sum() / total,\n",
|
||||
" above=spectrum[spectrum_centres > 16.5].sum() / total)\n",
|
||||
"print(f'15 keV line at {mu:.3f} keV, core sigma {abs(sig):.3f} keV; below 13.5 keV {fractions[\"below\"]*100:.2f} %, '\n",
|
||||
" f'13.5-16.5 keV {fractions[\"line\"]*100:.2f} %, above 16.5 keV {fractions[\"above\"]*100:.2f} %')\n",
|
||||
"fig, ax = plt.subplots(figsize=(7.5, 4.2))\n",
|
||||
"ax.semilogy(spectrum_centres, spectrum / total / np.diff(spectrum_centres)[0], lw=1)\n",
|
||||
"ax.axvline(15, color='grey', lw=.6, ls=':')\n",
|
||||
"ax.set_xlim(0, 30); ax.set_ylim(1e-6, 5)\n",
|
||||
"ax.set_xlabel('reconstructed photon energy [keV]'); ax.set_ylabel('photons / keV (normalised)')\n",
|
||||
"ax.set_title('Siemens star, both regions, GridBased 2-20 keV'); ax.grid(alpha=.3, which='both')\n",
|
||||
"fig.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "42d1185c",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-28T09:23:48.410840Z",
|
||||
"iopub.status.busy": "2026-09-28T09:23:48.410746Z",
|
||||
"iopub.status.idle": "2026-09-28T09:23:48.503131Z",
|
||||
"shell.execute_reply": "2026-09-28T09:23:48.502878Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"written /home/xie_x1/MLXID/GridBased/Results/overnight_poly2to20keV_Moench040/report/siemens_star_poly2to20keV_summary_50pct.json\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"summary = dict(parts=parts, frames=float(frames.sum()),\n",
|
||||
" photons=float(sum(s['n_photons'] for s in summaries)),\n",
|
||||
" model=summaries[0]['checkpoint'], epoch=summaries[0]['epoch'], crop=summaries[0]['crop'],\n",
|
||||
" regions={k: v['roi'] for k, v in REGIONS.items()}, photon_counts=counts,\n",
|
||||
" frc_cutoff=frc_results, line_keV=float(mu), line_sigma_keV=float(abs(sig)),\n",
|
||||
" spectrum_fractions=fractions)\n",
|
||||
"out = OVERNIGHT / 'report' / os.environ.get('GRID_STAR_SUMMARY', 'siemens_star_poly2to20keV_summary.json')\n",
|
||||
"out.parent.mkdir(parents=True, exist_ok=True)\n",
|
||||
"json.dump(summary, open(out, 'w'), indent=1)\n",
|
||||
"regions_dir = GRID / f'SiemensStar_15keV_{POLY_TAG}_regions' # the two regions as their own arrays\n",
|
||||
"regions_dir.mkdir(exist_ok=True)\n",
|
||||
"for region in REGIONS:\n",
|
||||
" np.save(regions_dir / f'{region}_binned_image_flattened.npy', images[region]['roi']['GridBased 2-20 keV'])\n",
|
||||
" np.save(regions_dir / f'{region}_binned_image.npy', cut_grid(raw, REGIONS[region]['roi']))\n",
|
||||
"json.dump(summary, open(regions_dir / 'summary.json', 'w'), indent=1)\n",
|
||||
"print('written', out)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "pytorch_nightly",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.18"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,583 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "32f9dbc8",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# XRF AgMo_1_factor_10 -- polychromatic GridBased model on measured lines\n",
|
||||
"\n",
|
||||
"2603 MaxIV, MOENCH014 at 150 V, full 400x400 chip flood-illuminated by the\n",
|
||||
"fluorescence of an Ag/Mo sample; slit factor 10, **0.67 % occupancy**, 1.0e8\n",
|
||||
"photons in 100 000 frames. Mo Ka 17.44 / Kb 19.64 and Ag Ka 22.10 keV sit in\n",
|
||||
"the middle of the 3-30 keV training range; Compton + elastic scatter forms a\n",
|
||||
"bump at 28-30 keV. The clean case -- `XRF_CuCrCo_1_factor_10.ipynb` has the\n",
|
||||
"low-energy lines.\n",
|
||||
"\n",
|
||||
"Model `Results/260919_poly3to30keV_Moench014_c96_00`, the default since\n",
|
||||
"2026-09-19: `[32, 64, 96, 96]`, flat 3-30 keV, chosen from four sizes in\n",
|
||||
"`Results/overnight_poly3to30keV/report`. Reconstruction from\n",
|
||||
"`scripts/05_infer_measurement.py --config Configs/infer_measurement_poly_Moench014.yaml\n",
|
||||
"--run AgMo_1_factor_10 --save-photons` (FP16, masked column common mode). The previous\n",
|
||||
"5-30 keV model's reconstructions are kept as `<run>_poly5to30`.\n",
|
||||
"Compared throughout:\n",
|
||||
"\n",
|
||||
"* **grid direct** -- the model output;\n",
|
||||
"* **grid corrected** -- $E = g^{-1}(E_\\mathrm{pred})$, where $g(E)$ is the MC\n",
|
||||
" position of a line of true energy $E$ (`scripts/07_energy_response.py`);\n",
|
||||
"* **classical 3x3** -- 3x3 sum around a local maximum on the same calibrated\n",
|
||||
" frames (first 10 000 frames), no model.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "930c69d4",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-19T09:10:13.369303Z",
|
||||
"iopub.status.busy": "2026-09-19T09:10:13.369219Z",
|
||||
"iopub.status.idle": "2026-09-19T09:10:13.639588Z",
|
||||
"shell.execute_reply": "2026-09-19T09:10:13.639268Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import json\n",
|
||||
"import sys\n",
|
||||
"from pathlib import Path\n",
|
||||
"\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"REPO = Path('/home/xie_x1/MLXID/GridBased')\n",
|
||||
"sys.path.insert(0, str(REPO / 'src'))\n",
|
||||
"from xrf_analysis import (EnergyCorrection, classical_and_model, fit_lines,\n",
|
||||
" line_centroid, load_reconstruction)\n",
|
||||
"\n",
|
||||
"CONFIG = REPO / 'Configs/infer_measurement_poly_Moench014.yaml'\n",
|
||||
"RUN = 'AgMo_1_factor_10'\n",
|
||||
"EXPERIMENT = REPO / 'Results/260919_poly3to30keV_Moench014_c96_00'\n",
|
||||
"RESPONSE = EXPERIMENT / 'energy_response.npz'\n",
|
||||
"GRID = Path('/mnt/sls_det_storage/moench_data/MLXID/InferenceResults/GridBased/XRF_2603MaxIV')\n",
|
||||
"EDGES = np.arange(0.0, 40.025, 0.05) # 50 eV bins\n",
|
||||
"CENTRES = 0.5 * (EDGES[1:] + EDGES[:-1])\n",
|
||||
"\n",
|
||||
"FIT_GROUPS = [ # each line fitted on its own window\n",
|
||||
" dict(label='Mo Ka', alpha=['Mo_Ka'], window=(16.0, 18.9)),\n",
|
||||
" dict(label='Mo Kb', alpha=['Mo_Kb'], window=(18.75, 20.7)),\n",
|
||||
" dict(label='Ag Ka', alpha=['Ag_Ka'], window=(20.6, 23.6)),\n",
|
||||
"] # Ag Kb sits on the rising Compton bump and is left out\n",
|
||||
"SPECTRUM_ZOOM = (14.5, 27.5)\n",
|
||||
"LINES = [n for g in FIT_GROUPS for n in g['alpha']]\n",
|
||||
"PEAKS = LINES + [e[0] for g in FIT_GROUPS for e in g.get('extra', ())]\n",
|
||||
"COLOURS = {'grid direct': '#1f6fb4', 'grid corrected': '#10695f',\n",
|
||||
" 'classical 3x3': '#6b6b6b'}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "81b6499b",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-19T09:10:13.641460Z",
|
||||
"iopub.status.busy": "2026-09-19T09:10:13.641283Z",
|
||||
"iopub.status.idle": "2026-09-19T09:10:20.295943Z",
|
||||
"shell.execute_reply": "2026-09-19T09:10:20.295634Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"AgMo_1_factor_10: 100000 frames, 1054 photons/frame, occupancy 0.69 %, 1.1 % of the photons below 3 keV\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"reconstruction = load_reconstruction(GRID, RUN)\n",
|
||||
"summary = reconstruction['summary']\n",
|
||||
"n_frames = summary['n_frames']\n",
|
||||
"energy = np.array(reconstruction['photons'][:, 2])\n",
|
||||
"correction = EnergyCorrection(RESPONSE) # core-based g\n",
|
||||
"correction_mean = EnergyCorrection(RESPONSE, estimator='mean')\n",
|
||||
"\n",
|
||||
"reference = classical_and_model(CONFIG, RUN, n_frames=10_000) # cached\n",
|
||||
"classical, grid_subset = reference['classical'], reference['grid']\n",
|
||||
"n_subset = int(reference['n_frames'])\n",
|
||||
"\n",
|
||||
"energies = {'grid direct': energy, 'grid corrected': correction(energy),\n",
|
||||
" 'classical 3x3': classical[:, 3]}\n",
|
||||
"frames_of = {'grid direct': n_frames, 'grid corrected': n_frames,\n",
|
||||
" 'classical 3x3': n_subset}\n",
|
||||
"print(f\"{RUN}: {n_frames} frames, {summary['photons_per_frame']:.0f} photons/frame, \"\n",
|
||||
" f\"occupancy {summary['occupancy_valid_region']*100:.2f} %, \"\n",
|
||||
" f\"{(energy < 3).mean()*100:.1f} % of the photons below 3 keV\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "f7b8cb19",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1. The MC energy response\n",
|
||||
"\n",
|
||||
"The energy head is a regression trained on a flat 3-30 keV spectrum. On MC\n",
|
||||
"(occupancy <= 2.5 %) the **core** of the predicted energy -- what a line fit\n",
|
||||
"measures -- stays within ~25 meV of the truth from 4 to 28 keV and moves only\n",
|
||||
"within ~0.75 keV of the edges (+98 meV at 3.2 keV, -93 meV at 29.6 keV), where\n",
|
||||
"the energy scale is also compressed. The **mean** is pulled towards the centre\n",
|
||||
"by ~0.1 keV at 5-12 keV and more near the edges, because the few per cent of\n",
|
||||
"photons whose energy is off by more than 1 keV (the tails) are cut by the\n",
|
||||
"bounded range. That mean is the `energy_bias_keV` of `eval_summary.json`. It\n",
|
||||
"is not a line shift, and correcting with it moves lines at 5-12 keV by ~0.1 keV\n",
|
||||
"the wrong way. The correction used here therefore inverts the core position\n",
|
||||
"$g(E)$; with the 3-30 keV model it matters only below ~4 keV."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "72f22c9b",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-19T09:10:20.297268Z",
|
||||
"iopub.status.busy": "2026-09-19T09:10:20.297102Z",
|
||||
"iopub.status.idle": "2026-09-19T09:10:20.563301Z",
|
||||
"shell.execute_reply": "2026-09-19T09:10:20.563003Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Mo_Ka: g - E = -12 meV, g' = 1.00, MC core sigma 0.275 keV\n",
|
||||
"Mo_Kb: g - E = -8 meV, g' = 1.00, MC core sigma 0.290 keV\n",
|
||||
"Ag_Ka: g - E = -6 meV, g' = 1.00, MC core sigma 0.301 keV\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1300x420 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"response = np.load(RESPONSE)\n",
|
||||
"centre = response['table_centre']\n",
|
||||
"figure, axes = plt.subplots(1, 2, figsize=(13, 4.2))\n",
|
||||
"for curve, colour, label in ((correction, COLOURS['grid corrected'], 'core of E_pred (used)'),\n",
|
||||
" (correction_mean, '#c0392b', 'mean of E_pred')):\n",
|
||||
" axes[0].plot(curve.grid, curve.g_grid - curve.grid, color=colour, lw=1.5, label=label)\n",
|
||||
"for name in LINES:\n",
|
||||
" axes[0].axvline(line_centroid(name), color='k', lw=.5, ls=':')\n",
|
||||
"axes[0].axhline(0, color='k', lw=.6); axes[0].set_ylim(-0.6, 0.3)\n",
|
||||
"axes[0].set_xlabel('E_true [keV]'); axes[0].set_ylabel('g(E) - E [keV]')\n",
|
||||
"axes[0].set_title('MC: where a line of true energy E appears'); axes[0].legend(fontsize=8)\n",
|
||||
"axes[0].grid(alpha=.3)\n",
|
||||
"axes[1].plot(centre, response['table_core_sigma'], 'k.', ms=3, label='core sigma, raw')\n",
|
||||
"axes[1].plot(correction.grid, correction.mc_sigma(correction.grid) / correction.slope(correction.grid),\n",
|
||||
" color=COLOURS['grid corrected'], lw=1.2, label=\"core sigma / g' (true keV)\")\n",
|
||||
"axes[1].set_ylim(0, 0.4); axes[1].set_xlabel('E_true [keV]'); axes[1].set_ylabel('keV')\n",
|
||||
"axes[1].set_title('MC: energy resolution'); axes[1].legend(fontsize=8); axes[1].grid(alpha=.3)\n",
|
||||
"figure.tight_layout()\n",
|
||||
"for name in LINES:\n",
|
||||
" e = line_centroid(name)\n",
|
||||
" print(f\"{name}: g - E = {(correction.forward(np.array([e]))[0] - e)*1000:+.0f} meV, \"\n",
|
||||
" f\"g' = {correction.slope(e):.2f}, MC core sigma {correction.mc_sigma(e):.3f} keV\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "dd0b6fa5",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2. Spectra\n",
|
||||
"\n",
|
||||
"Per frame, 50 eV bins; grey = outside the 3-30 keV training range."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "5b61a197",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-19T09:10:20.564617Z",
|
||||
"iopub.status.busy": "2026-09-19T09:10:20.564520Z",
|
||||
"iopub.status.idle": "2026-09-19T09:10:25.475927Z",
|
||||
"shell.execute_reply": "2026-09-19T09:10:25.475651Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1400x850 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"histograms = {name: np.histogram(values, EDGES)[0] for name, values in energies.items()}\n",
|
||||
"figure, axes = plt.subplots(2, 1, figsize=(14, 8.5))\n",
|
||||
"for axis, log in zip(axes, (True, False)):\n",
|
||||
" for name, counts in histograms.items():\n",
|
||||
" axis.plot(CENTRES, counts / frames_of[name], lw=1, color=COLOURS[name], label=name)\n",
|
||||
" for name in LINES:\n",
|
||||
" axis.axvline(line_centroid(name), color='k', lw=.4, ls='--')\n",
|
||||
" axis.axvspan(0, 3, color='0.9'); axis.axvspan(30, 40, color='0.9')\n",
|
||||
" axis.set_xlabel('energy [keV]'); axis.set_ylabel('photons / frame / 50 eV')\n",
|
||||
" axis.grid(alpha=.3)\n",
|
||||
" if log:\n",
|
||||
" axis.set_yscale('log'); axis.set_xlim(2, 33); axis.set_ylim(1e-4, None)\n",
|
||||
" axis.legend(fontsize=9); axis.set_title(RUN)\n",
|
||||
" else:\n",
|
||||
" axis.set_xlim(*SPECTRUM_ZOOM)\n",
|
||||
"figure.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7cce07c1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3. Line positions and energy resolution\n",
|
||||
"\n",
|
||||
"Grid lines: Gaussian core + a wide Gaussian at the same position (the tails of\n",
|
||||
"section 1) + an erfc low-energy step, on an exp(polynomial) background.\n",
|
||||
"Classical lines: Gaussian + step. Ka is fitted as the tabulated doublet, so the\n",
|
||||
"position is the intensity-weighted centroid. `sigma` is the core width; FWHM is\n",
|
||||
"that of the whole line shape."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "07db24a1",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-19T09:10:25.477272Z",
|
||||
"iopub.status.busy": "2026-09-19T09:10:25.477178Z",
|
||||
"iopub.status.idle": "2026-09-19T09:10:25.617926Z",
|
||||
"shell.execute_reply": "2026-09-19T09:10:25.617645Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
" table | position [keV] | core sigma [keV] | FWHM [keV] | MC sigma\n",
|
||||
" | direct corr. 3x3 | direct corr. 3x3 | grid 3x3 ratio |\n",
|
||||
"Mo_Ka 17.44 | 17.47 17.48 17.52 | 0.327 0.327 0.464 | 0.82 1.09 0.75 | 0.275\n",
|
||||
"Mo_Kb 19.64 | 19.66 19.67 19.74 | 0.353 0.352 0.492 | 0.83 1.16 0.72 | 0.290\n",
|
||||
"Ag_Ka 22.10 | 22.10 22.11 22.17 | 0.378 0.378 0.489 | 0.95 1.15 0.82 | 0.301\n",
|
||||
"grid FWHM: direct output\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"fits = {}\n",
|
||||
"for variant, counts in histograms.items():\n",
|
||||
" for group in FIT_GROUPS:\n",
|
||||
" fits[variant, group['label']] = fit_lines(\n",
|
||||
" CENTRES, counts, group['alpha'], group.get('beta'), window=group['window'],\n",
|
||||
" beta_ratio_fixed=group.get('ratio_fixed'),\n",
|
||||
" fit_stretch=group.get('fit_stretch', True), extra_peaks=group.get('extra', ()),\n",
|
||||
" tails=variant != 'classical 3x3')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def peak(variant, name):\n",
|
||||
" group = next(g for g in FIT_GROUPS\n",
|
||||
" if name in g['alpha'] or name in [e[0] for e in g.get('extra', ())])\n",
|
||||
" return fits[variant, group['label']]['lines'][name]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def fwhm_of(variant, name):\n",
|
||||
" \"\"\"FWHM of the line shape; for the extra peaks (no doublet) from sigma.\"\"\"\n",
|
||||
" line = peak(variant, name)\n",
|
||||
" return line.get('fwhm', 2.3548 * line['sigma'])\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print(f\"{'':8s} {'table':>6s} | {'position [keV]':^26s} | {'core sigma [keV]':^26s} | \"\n",
|
||||
" f\"{'FWHM [keV]':^20s} | MC sigma\")\n",
|
||||
"print(f\"{'':8s} {'':>6s} | {'direct':>8s} {'corr.':>8s} {'3x3':>8s} | \"\n",
|
||||
" f\"{'direct':>8s} {'corr.':>8s} {'3x3':>8s} | {'grid':>6s} {'3x3':>6s} {'ratio':>6s} |\")\n",
|
||||
"for name in PEAKS:\n",
|
||||
" table = f\"{line_centroid(name):6.2f}\" if name in LINES else f\"{'':6s}\"\n",
|
||||
" positions = [peak(v, name)['mu'] for v in energies]\n",
|
||||
" sigmas = [peak(v, name)['sigma'] for v in energies]\n",
|
||||
" grid_fwhm = fwhm_of('grid direct', name)\n",
|
||||
" classical_fwhm = fwhm_of('classical 3x3', name)\n",
|
||||
" mc = correction.mc_sigma(line_centroid(name)) if name in LINES else \\\n",
|
||||
" correction.mc_sigma(peak('grid corrected', name)['mu'])\n",
|
||||
" print(f\"{name:8s} {table} | \" + ' '.join(f'{p:8.2f}' for p in positions) + ' | ' +\n",
|
||||
" ' '.join(f'{s:8.3f}' for s in sigmas) +\n",
|
||||
" f\" | {grid_fwhm:6.2f} {classical_fwhm:6.2f} {grid_fwhm/classical_fwhm:6.2f} | {mc:.3f}\")\n",
|
||||
"print('grid FWHM: direct output')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "cc95eb5a",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-19T09:10:25.619193Z",
|
||||
"iopub.status.busy": "2026-09-19T09:10:25.619065Z",
|
||||
"iopub.status.idle": "2026-09-19T09:10:26.626942Z",
|
||||
"shell.execute_reply": "2026-09-19T09:10:26.626658Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAACkYAAAJOCAYAAADoTSlEAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd3gU5frG8e9ueg8QCBBC770FqVIEBKUpCIJBEBsSUI7HgtgL2LERUIogARSkKQpIl947SAkQEmogBNLb7vz+4GeOSC/JJJv7c11cx53dnb1n9MzDu/vM+1oMwzAQEREREREREREREREREREREREREXEAVrMDiIiIiIiIiIiIiIiIiIiIiIiIiIjcLWqMFBERERERERERERERERERERERERGHocZIEREREREREREREREREREREREREXEYaowUEREREREREREREREREREREREREYehxkgRERERERERERERERERERERERERcRhqjBQRERERERERERERERERERERERERh6HGSBERERERERERERERERERERERERFxGGqMFBERERERERERERERERERERERERGHocZIEREREREREREREREREREREREREXEYaoyUAq9jx46MGTPmms9369aNd95556b398/Xr169mlKlSt1hQhERkUvKli3LvHnzcmz/AwcO5NVXX73j/UyePJm6deveeSAREZEb0Hgud7zzzjt069bN7BgiIvmWxnL5W6tWrfjyyy/NjiEi4pA0phMRkfxC4zqR/EmNkVLgLVy4kEGDBuXIvlu0aMHx48dzZN9RUVFYLBYuXLhwS+8rW7YsFouFQ4cOXbY9LCwMi8Vy21/y/fuHspSUFDp27Mi9997LxYsXb2ufIiKSu7799ls+/vjjHP+cIUOGEBwcjK+vL0FBQQwdOpSMjIybeu/ChQupVasWhQoVonDhwrRr147du3ff9Gf/XT/LlCmD3W6/7LmaNWtisVjYsWPHrRxOtn//WHb48GHKly/PCy+8gGEYt7VPERG5Po3nLtF4TkSkYNNYTmM5EZH8qqCN6f7Wpk0bPDw8iI+Pv6Mc/25+sdlsDBgwgOrVq3PixIk72reIiOSugjCu+1tycjK+vr7cc889t/zef+vfvz9Dhw7Nfnz27FkaNGjAI488ctPHJY5NjZFSYBmGgc1mMzVDVlaWKZ9bpUoV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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 2640x600 with 12 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"shown = ('grid direct', 'classical 3x3')\n",
|
||||
"figure, axes = plt.subplots(2, len(FIT_GROUPS) * 2, figsize=(4.4 * len(FIT_GROUPS) * 2, 6),\n",
|
||||
" gridspec_kw=dict(height_ratios=[3, 1]), squeeze=False)\n",
|
||||
"for column, (group, variant) in enumerate((g, v) for g in FIT_GROUPS for v in shown):\n",
|
||||
" fit = fits[variant, group['label']]\n",
|
||||
" x = fit['centres']\n",
|
||||
" axes[0, column].plot(x, fit['counts'], 'k.', ms=2.5)\n",
|
||||
" axes[0, column].plot(x, fit['model'](x), color=COLOURS[variant], lw=1.3)\n",
|
||||
" for part, curve in fit['components'](x).items():\n",
|
||||
" axes[0, column].plot(x, curve, lw=.7, ls='--', label=part)\n",
|
||||
" axes[0, column].set_yscale('log')\n",
|
||||
" axes[0, column].set_ylim(max(fit['counts'].min() * 0.5, 1), fit['counts'].max() * 2)\n",
|
||||
" axes[0, column].set_title(f\"{variant}: {group['label']}\", fontsize=9)\n",
|
||||
" axes[0, column].legend(fontsize=6)\n",
|
||||
" axes[1, column].plot(x, (fit['counts'] - fit['model'](x)) / np.sqrt(np.maximum(fit['counts'], 1)),\n",
|
||||
" '.', ms=2.5, color=COLOURS[variant])\n",
|
||||
" axes[1, column].axhline(0, color='k', lw=.6)\n",
|
||||
" axes[1, column].set_xlabel('energy [keV]'); axes[1, column].set_ylabel('pull')\n",
|
||||
"figure.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "8327278e",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-19T09:10:26.628157Z",
|
||||
"iopub.status.busy": "2026-09-19T09:10:26.628054Z",
|
||||
"iopub.status.idle": "2026-09-19T09:10:26.732058Z",
|
||||
"shell.execute_reply": "2026-09-19T09:10:26.731776Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 750x440 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"figure, axis = plt.subplots(figsize=(7.5, 4.4))\n",
|
||||
"for offset, variant in zip((-0.08, 0.0, 0.08), energies):\n",
|
||||
" axis.errorbar([line_centroid(n) + offset for n in LINES],\n",
|
||||
" [peak(variant, n)['sigma'] for n in LINES],\n",
|
||||
" [peak(variant, n)['sigma_err'] for n in LINES],\n",
|
||||
" fmt='o', ms=5, capsize=3, color=COLOURS[variant], label=variant)\n",
|
||||
"e = np.linspace(min(line_centroid(n) for n in LINES) - 1, max(line_centroid(n) for n in LINES) + 1, 200)\n",
|
||||
"e = e[(e >= 5) & (e <= 30)]\n",
|
||||
"axis.plot(e, correction.mc_sigma(e), 'k--', lw=1, label='MC core sigma (raw)')\n",
|
||||
"axis.plot(e, correction.mc_sigma(e) / correction.slope(e), 'k:', lw=1, label=\"MC / g' (true keV)\")\n",
|
||||
"axis.set_xlabel('line energy [keV]'); axis.set_ylabel('core sigma [keV]'); axis.set_ylim(0, None)\n",
|
||||
"axis.set_title('energy resolution'); axis.legend(fontsize=8); axis.grid(alpha=.3)\n",
|
||||
"figure.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "fadc5f4d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4. Reconstruction efficiency\n",
|
||||
"\n",
|
||||
"Without truth, three handles on the 10 000 frames of the classical reference:\n",
|
||||
"\n",
|
||||
"* **isolated photons**: classical clusters with no other cluster within 4 px\n",
|
||||
" that have a grid photon within 1.5 px. Above 5 keV the 2.5 keV classical\n",
|
||||
" threshold finds every isolated photon, so this is the absolute efficiency.\n",
|
||||
" The MC equivalent is photons with no neighbour within 4 px.\n",
|
||||
"* **pile-up**: classical clusters holding two or more grid photons within 2 px.\n",
|
||||
"* **energy balance**: summed reconstructed energy / deposited energy per frame\n",
|
||||
" (calibrated frame minus its baseline)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "af106e1d",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-19T09:10:26.733295Z",
|
||||
"iopub.status.busy": "2026-09-19T09:10:26.733190Z",
|
||||
"iopub.status.idle": "2026-09-19T09:10:27.674956Z",
|
||||
"shell.execute_reply": "2026-09-19T09:10:27.674675Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"isolated photons >= 5 keV found: 99.97 % (3-5 keV: 92.9 %; MC: 99.96 %)\n",
|
||||
"grid / classical photon count: 1.091\n",
|
||||
"classical clusters with >= 2 grid photons: 8.5 % (Poisson, second photon within 2 px: 8.3 %)\n",
|
||||
"energy balance: grid 0.9968, classical 0.9980\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 750x420 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"match = reference['classical_match']\n",
|
||||
"found = match >= 0\n",
|
||||
"isolated = reference['isolation_classical'] > 4.0\n",
|
||||
"above5 = classical[:, 3] >= 5\n",
|
||||
"edges_e = np.arange(2.5, 30.01, 0.5)\n",
|
||||
"which = np.digitize(classical[:, 3], edges_e) - 1\n",
|
||||
"fraction = np.array([found[isolated & (which == i)].mean() if (isolated & (which == i)).sum() > 200\n",
|
||||
" else np.nan for i in range(len(edges_e) - 1)])\n",
|
||||
"\n",
|
||||
"mc = json.load(open(EXPERIMENT / 'eval_summary.json'))['1%']['pair']\n",
|
||||
"far = [i for i, edge in enumerate(mc['edges']) if edge >= 4.0]\n",
|
||||
"mc_isolated = sum(mc['n_match'][i] for i in far) / sum(mc['n_true'][i] for i in far)\n",
|
||||
"\n",
|
||||
"figure, axis = plt.subplots(figsize=(7.5, 4.2))\n",
|
||||
"axis.plot(0.5 * (edges_e[1:] + edges_e[:-1]), fraction * 100, 'o-', ms=3,\n",
|
||||
" color=COLOURS['grid direct'], label='isolated classical clusters found by the grid')\n",
|
||||
"axis.axhline(mc_isolated * 100, color='k', ls='--', lw=1, label='MC, isolated photons, 1 %')\n",
|
||||
"axis.axvspan(0, 3, color='0.9'); axis.set_ylim(90, 100.5); axis.set_xlim(2.5, 30)\n",
|
||||
"axis.set_xlabel('classical 3x3 energy [keV]'); axis.set_ylabel('%')\n",
|
||||
"axis.set_title('detection efficiency'); axis.legend(fontsize=8); axis.grid(alpha=.3)\n",
|
||||
"figure.tight_layout()\n",
|
||||
"\n",
|
||||
"multiplicity = reference['grid_per_classical']\n",
|
||||
"occupancy = summary['occupancy_valid_region']\n",
|
||||
"balance = reference['balance'][:, 1].sum()\n",
|
||||
"low = (classical[:, 3] >= 3) & ~above5\n",
|
||||
"print(f\"isolated photons >= 5 keV found: {found[isolated & above5].mean()*100:.2f} % \"\n",
|
||||
" f\"(3-5 keV: {found[isolated & low].mean()*100:.1f} %; MC: {mc_isolated*100:.2f} %)\")\n",
|
||||
"print(f\"grid / classical photon count: {len(grid_subset) / len(classical):.3f}\")\n",
|
||||
"print(f\"classical clusters with >= 2 grid photons: {(multiplicity >= 2).mean()*100:.1f} % \"\n",
|
||||
" f\"(Poisson, second photon within 2 px: {(1 - np.exp(-occupancy * np.pi * 4))*100:.1f} %)\")\n",
|
||||
"print(f\"energy balance: grid {grid_subset[:, 3].sum() / balance:.4f}, \"\n",
|
||||
" f\"classical {classical[:, 3].sum() / balance:.4f}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "16e3c938",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Conclusions\n",
|
||||
"\n",
|
||||
"* **Lines.** All resolved; the grid puts them within 0.03 keV of the tables,\n",
|
||||
" the classical 3x3 sum 0.06-0.10 keV high (the MOENCH014 LUT reads 0.3-0.5 %\n",
|
||||
" high here). The MC-based correction changes nothing at these energies\n",
|
||||
" (<= 12 meV).\n",
|
||||
"* **Energy resolution.** FWHM 0.82 / 0.83 / 0.95 keV for Mo Ka / Mo Kb /\n",
|
||||
" Ag Ka against 1.09 / 1.16 / 1.15 keV for the classical sum, 18-28 %\n",
|
||||
" narrower. The core widths (0.33-0.38 keV) are 19-26 % above the MC\n",
|
||||
" (0.28-0.30 keV): at these energies the data carry an extra term of ~1 % of E\n",
|
||||
" (pixel-to-pixel gain residuals of the calibration, not in the MC). The same\n",
|
||||
" holds for the previous 5-30 keV model.\n",
|
||||
"* **Efficiency.** 99.97 % of the isolated photons above 5 keV (MC 99.96 %).\n",
|
||||
" The grid finds 9.1 % more photons than the classical finder: pile-up the 3x3\n",
|
||||
" finder merges (8.5 % of its clusters hold two grid photons, 8.3 % expected\n",
|
||||
" from Poisson), plus low-energy photons that the 3-30 keV model now reports.\n",
|
||||
" Energy balance 0.997."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "a8e470c1",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-19T09:10:27.676156Z",
|
||||
"iopub.status.busy": "2026-09-19T09:10:27.676067Z",
|
||||
"iopub.status.idle": "2026-09-19T09:10:27.708535Z",
|
||||
"shell.execute_reply": "2026-09-19T09:10:27.708203Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"output = dict(\n",
|
||||
" run=RUN, epoch=summary['epoch'], n_frames=n_frames,\n",
|
||||
" photons_per_frame=summary['photons_per_frame'], occupancy=occupancy,\n",
|
||||
" lines={name: {variant: dict(mu=float(peak(variant, name)['mu']),\n",
|
||||
" sigma=float(peak(variant, name)['sigma']),\n",
|
||||
" fwhm=float(fwhm_of(variant, name)))\n",
|
||||
" for variant in energies}\n",
|
||||
" for name in PEAKS},\n",
|
||||
" efficiency_isolated_above5keV=float(found[isolated & above5].mean()),\n",
|
||||
" efficiency_isolated_mc=mc_isolated,\n",
|
||||
" grid_over_classical_count=len(grid_subset) / len(classical),\n",
|
||||
" energy_balance_grid=float(grid_subset[:, 3].sum() / balance),\n",
|
||||
")\n",
|
||||
"with open(GRID / RUN / 'xrf_energy_analysis.json', 'w') as handle:\n",
|
||||
" json.dump(output, handle, indent=1)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "pytorch_nightly",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.18"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,591 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a4f1f029",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# XRF CuCrCo_1_factor_10 -- polychromatic GridBased model on measured lines\n",
|
||||
"\n",
|
||||
"2603 MaxIV, MOENCH014 at 150 V, full 400x400 chip flood-illuminated by the\n",
|
||||
"fluorescence of a Cu/Cr/Co sample under a 12 keV beam; slit factor 10,\n",
|
||||
"**1.28 % occupancy**, 2.0e8 photons in 100 000 frames. Cr 5.41, Co 6.93 and\n",
|
||||
"Cu 8.04 keV Ka lines 1.1-1.5 keV apart with their Kb lines in between (Co Kb\n",
|
||||
"0.39 keV below Cu Ka), plus the elastic line at 12 keV. Cr Ka sat 0.4 keV\n",
|
||||
"above the lower edge of the previous 5-30 keV model, which biased and\n",
|
||||
"compressed it; the 3-30 keV model puts it 2.4 keV inside its range.\n",
|
||||
"`XRF_AgMo_1_factor_10.ipynb` has the high-energy lines.\n",
|
||||
"\n",
|
||||
"Model `Results/260919_poly3to30keV_Moench014_c96_00`, the default since\n",
|
||||
"2026-09-19: `[32, 64, 96, 96]`, flat 3-30 keV, chosen from four sizes in\n",
|
||||
"`Results/overnight_poly3to30keV/report`. Reconstruction from\n",
|
||||
"`scripts/05_infer_measurement.py --config Configs/infer_measurement_poly_Moench014.yaml\n",
|
||||
"--run CuCrCo_1_factor_10 --save-photons` (FP16, masked column common mode). The previous\n",
|
||||
"5-30 keV model's reconstructions are kept as `<run>_poly5to30`.\n",
|
||||
"Compared throughout:\n",
|
||||
"\n",
|
||||
"* **grid direct** -- the model output;\n",
|
||||
"* **grid corrected** -- $E = g^{-1}(E_\\mathrm{pred})$, where $g(E)$ is the MC\n",
|
||||
" position of a line of true energy $E$ (`scripts/07_energy_response.py`);\n",
|
||||
"* **classical 3x3** -- 3x3 sum around a local maximum on the same calibrated\n",
|
||||
" frames (first 10 000 frames), no model.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "865cec36",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-19T09:10:29.570680Z",
|
||||
"iopub.status.busy": "2026-09-19T09:10:29.570598Z",
|
||||
"iopub.status.idle": "2026-09-19T09:10:29.817584Z",
|
||||
"shell.execute_reply": "2026-09-19T09:10:29.817269Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import json\n",
|
||||
"import sys\n",
|
||||
"from pathlib import Path\n",
|
||||
"\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"REPO = Path('/home/xie_x1/MLXID/GridBased')\n",
|
||||
"sys.path.insert(0, str(REPO / 'src'))\n",
|
||||
"from xrf_analysis import (EnergyCorrection, classical_and_model, fit_lines,\n",
|
||||
" line_centroid, load_reconstruction)\n",
|
||||
"\n",
|
||||
"CONFIG = REPO / 'Configs/infer_measurement_poly_Moench014.yaml'\n",
|
||||
"RUN = 'CuCrCo_1_factor_10'\n",
|
||||
"EXPERIMENT = REPO / 'Results/260919_poly3to30keV_Moench014_c96_00'\n",
|
||||
"RESPONSE = EXPERIMENT / 'energy_response.npz'\n",
|
||||
"GRID = Path('/mnt/sls_det_storage/moench_data/MLXID/InferenceResults/GridBased/XRF_2603MaxIV')\n",
|
||||
"EDGES = np.arange(0.0, 40.025, 0.05) # 50 eV bins\n",
|
||||
"CENTRES = 0.5 * (EDGES[1:] + EDGES[:-1])\n",
|
||||
"\n",
|
||||
"FIT_GROUPS = [\n",
|
||||
" # one joint fit; each Kb tied to its Ka with the tabulated offset. Co Kb\n",
|
||||
" # cannot be separated from Cu Ka, so its Kb/Ka ratio is fixed at 0.135.\n",
|
||||
" dict(label='Cr/Co/Cu K', alpha=['Cr_Ka', 'Co_Ka', 'Cu_Ka'],\n",
|
||||
" beta={'Cr_Kb': 'Cr_Ka', 'Co_Kb': 'Co_Ka', 'Cu_Kb': 'Cu_Ka'},\n",
|
||||
" ratio_fixed={'Co_Kb': 0.135}, fit_stretch=False, window=(4.85, 9.6)),\n",
|
||||
" dict(label='elastic', alpha=[], extra=[('elastic', 12.0)], window=(10.9, 13.2)),\n",
|
||||
"]\n",
|
||||
"SPECTRUM_ZOOM = (4.0, 13.5)\n",
|
||||
"LINES = [n for g in FIT_GROUPS for n in g['alpha']]\n",
|
||||
"PEAKS = LINES + [e[0] for g in FIT_GROUPS for e in g.get('extra', ())]\n",
|
||||
"COLOURS = {'grid direct': '#1f6fb4', 'grid corrected': '#10695f',\n",
|
||||
" 'classical 3x3': '#6b6b6b'}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "b782342f",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-19T09:10:29.819386Z",
|
||||
"iopub.status.busy": "2026-09-19T09:10:29.819219Z",
|
||||
"iopub.status.idle": "2026-09-19T09:10:40.369835Z",
|
||||
"shell.execute_reply": "2026-09-19T09:10:40.369529Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"CuCrCo_1_factor_10: 100000 frames, 1985 photons/frame, occupancy 1.29 %, 0.7 % of the photons below 3 keV\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"reconstruction = load_reconstruction(GRID, RUN)\n",
|
||||
"summary = reconstruction['summary']\n",
|
||||
"n_frames = summary['n_frames']\n",
|
||||
"energy = np.array(reconstruction['photons'][:, 2])\n",
|
||||
"correction = EnergyCorrection(RESPONSE) # core-based g\n",
|
||||
"correction_mean = EnergyCorrection(RESPONSE, estimator='mean')\n",
|
||||
"\n",
|
||||
"reference = classical_and_model(CONFIG, RUN, n_frames=10_000) # cached\n",
|
||||
"classical, grid_subset = reference['classical'], reference['grid']\n",
|
||||
"n_subset = int(reference['n_frames'])\n",
|
||||
"\n",
|
||||
"energies = {'grid direct': energy, 'grid corrected': correction(energy),\n",
|
||||
" 'classical 3x3': classical[:, 3]}\n",
|
||||
"frames_of = {'grid direct': n_frames, 'grid corrected': n_frames,\n",
|
||||
" 'classical 3x3': n_subset}\n",
|
||||
"print(f\"{RUN}: {n_frames} frames, {summary['photons_per_frame']:.0f} photons/frame, \"\n",
|
||||
" f\"occupancy {summary['occupancy_valid_region']*100:.2f} %, \"\n",
|
||||
" f\"{(energy < 3).mean()*100:.1f} % of the photons below 3 keV\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d8f721c4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 1. The MC energy response\n",
|
||||
"\n",
|
||||
"The energy head is a regression trained on a flat 3-30 keV spectrum. On MC\n",
|
||||
"(occupancy <= 2.5 %) the **core** of the predicted energy -- what a line fit\n",
|
||||
"measures -- stays within ~25 meV of the truth from 4 to 28 keV and moves only\n",
|
||||
"within ~0.75 keV of the edges (+98 meV at 3.2 keV, -93 meV at 29.6 keV), where\n",
|
||||
"the energy scale is also compressed. The **mean** is pulled towards the centre\n",
|
||||
"by ~0.1 keV at 5-12 keV and more near the edges, because the few per cent of\n",
|
||||
"photons whose energy is off by more than 1 keV (the tails) are cut by the\n",
|
||||
"bounded range. That mean is the `energy_bias_keV` of `eval_summary.json`. It\n",
|
||||
"is not a line shift, and correcting with it moves lines at 5-12 keV by ~0.1 keV\n",
|
||||
"the wrong way. The correction used here therefore inverts the core position\n",
|
||||
"$g(E)$; with the 3-30 keV model it matters only below ~4 keV."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "a9ff6281",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-19T09:10:40.371116Z",
|
||||
"iopub.status.busy": "2026-09-19T09:10:40.370965Z",
|
||||
"iopub.status.idle": "2026-09-19T09:10:40.638231Z",
|
||||
"shell.execute_reply": "2026-09-19T09:10:40.637990Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Cr_Ka: g - E = -7 meV, g' = 1.00, MC core sigma 0.256 keV\n",
|
||||
"Co_Ka: g - E = +0 meV, g' = 1.00, MC core sigma 0.264 keV\n",
|
||||
"Cu_Ka: g - E = +2 meV, g' = 1.00, MC core sigma 0.267 keV\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAABQoAAAGZCAYAAADB4AymAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd1zU9R/A8dexN6KAA5WhOAER956pZc5M03Kkmf6szLRlWrlKSzNLMzNLc+TKVWbuieIWFFFEBXEgIMo89n1/fxCXJyCgwAG+n48HD+V7n/us7wGfe99nqBRFURBCCCGEEEIIIYQQQjzTDPRdASGEEEIIIYQQQgghhP5JoFAIIYQQQgghhBBCCCGBQiGEEEIIIYQQQgghhAQKhRBCCCGEEEIIIYQQSKBQCCGEEEIIIYQQQgiBBAqFEEIIIYQQQgghhBBIoFAIIYQQQgghhBBCCIEECoUQQgghhBBCCCGEEEigUAghhBBCCCGEEEIIgQQKRTm0YsUKVCoVKpWKgwcP5nhcURRq166NSqWiY8eOOR6Pj4/niy++oGnTptjY2GBqaoqLiwsjR47k7Nmzxd+Ah7i4uPDiiy+WaJn6MG3aNFQqlc61jh075np/SpP79+/zyiuv4OjoiEqlom/fvnmmXbx4MStWrCixuomCy/59kdvXiBEj9F09IYQQQm/K07haFL3cxvAFFRQUxLRp0wgLC8vx2IgRI3BxcXm6ygkhnpiRvisgRHGxtrbml19+yTFoOXToENeuXcPa2jrHc65du0a3bt2Iiopi7NixTJ8+HSsrK8LCwtiwYQNNmjQhNjYWW1vbEmrFs2vx4sX6rkK+Zs6cyZYtW/j111+pVasWFStWzDPt4sWLsbe3l8BTKTVgwAAmTZqU47qDg4MeaiOEEEKULjKuFkUtKCiI6dOn07FjxxxBwU8//ZR3331XPxUTQkigUJRfgwYNYs2aNfzwww/Y2Nhor//yyy+0atWK+Ph4nfSZmZn069ePe/fu4efnh4eHh/axDh06MHz4cP755x+MjY1LrA0lITMzk4yMDExNTfVdFR0NGjTQdxXyFRgYSK1atXj11VeLNN/09HRUKhVGRs/mr+jk5GTMzMye+BPqJ1G5cmVatmxZYuWVJfq4H0IIIUoXGVfnTa1WY2Fhobfyy+O4sVatWvqughDPNFl6LMqtwYMHA7B27Vrttbi4ODZt2sTIkSNzpN+6dSsXLlxg8uTJOoOZhz3//POFHghcvHgRlUrFxo0btdfOnDmDSqWiYcOGOml79+5NkyZNcuSxc+dOfHx8MDc3p169evz666850ty9e5cxY8ZQvXp1TExMcHV1Zfr06WRkZGjThIWFoVKp+Prrr5k1axaurq6Ymppy4MABAE6fPk3v3r2pWLEiZmZmNG7cmA0bNhSondOnT6dFixZUrFgRGxsbfHx8+OWXX1AUpUDPf9SjS4+z6z5v3jzmz5+Pq6srVlZWtGrViuPHj+d4/tO05f79+4wbNw4nJydMTExwc3NjypQppKam6tRl7969XLp06bFLciBrCfnFixc5dOiQNm32J6cHDx5EpVKxatUqJk2ahJOTE6amply9ejXP5RzZy4AeXaqxfv16WrVqhaWlJVZWVnTv3p1z584VqM2Fef0U5T3Ibsvu3bsZOXIkDg4OWFhYkJqaiqIofPnllzg7O2NmZkbTpk3Zs2ePzmsjMTGRChUqMGbMmBzlh4WFYWhoyNy5cwvUB08iOjqacePG0aBBA6ysrHB0dKRz584cOXIkR12yf/a++OILatasqW3Tvn37dNJm3/dz587Rv39/bGxssLW15bXXXiM6OjpHHQpy30+fPs0rr7yCi4sL5ubmuLi4MHjwYG7cuKGT7nH3Izo6mjfffJMaNWpgamqKg4MDbdq0Ye/evUXUm0IIIUqr0jKuzhYSEsKQIUNwdHTE1NSU+vXr88MPP+ikyR5jrV27lilTplCtWjVsbGzo2rUrwcHBOfLcu3cvXbp0wcbGBgsLC9q0aZPn3+izZ88yYMAA7OzstEGt1NRUJk2aRJUqVbCwsKB9+/acOXMGFxcX7YqSsLAwjIyMmD17do7yDx8+nOM9w6MeN24saBsK+vf8119/pVGjRpiZmVGxYkX69evHpUuX8qxbNpVKxbRp03Jcf7gfVqxYwcsvvwxAp06dtOPj7G16clt6nJKSwuTJk3F1dcXExAQnJyfeeustYmNjc5Tz4osvFuj9kxAidxIoFOWWjY0NAwYM0PmjsHbtWgwMDBg0aFCO9Lt37wZ47D5zj8prP5aHNWzYkKpVq+r88d27dy/m5uYEBQVx584dADIyMjh06BBdu3bVeX5AQACTJk3ivffeY9u2bXh5eTFq1CgOHz6sTXP37l2aN2/Orl27+Oyzz/jnn38YNWoUs2fPZvTo0Tnq9P3337N//37mzZvHP//8Q7169Thw4ABt2rQhNjaWJUuWsG3bNry9vRk0aFCB9tYLCwtjzJgxbNiwgc2bN9O/f3/eeecdZs6cme9zC+OHH35gz549LFiwgDVr1pCUlMQLL7xAXFycNs3TtCUlJYVOnTqxcuVKJk6cyN9//81rr73G119/Tf/+/QGoWrUqfn5+NG7cGDc3N/z8/PDz88PHxyfXPLds2YKbmxuNGzfWpt2yZYtOmsmTJxMeHs6SJUv466+/cHR0LFS/fPnllwwePJgGDRqwYcMGVq1aRUJCAu3atSMoKOixzy3s66c47sHIkSMxNjZm1apV/PHHHxgbGzNlyhSmTJlCjx492LZtG2PHjuWNN97gypUr2udZWVkxcuRI1qxZo1M+ZC33NjExyfUNzKMURSEjIyPHV36B7vv37wPw+eef8/fff7N8+XLc3Nzo2LFjroHjRYsWsXPnThYsWMDq1asxMDDg+eefx8/PL0fafv36Ubt2bf744w+mTZvG1q1b6d69O+np6do0Bb3vYWFh1K1blwULFrBr1y6++uorIiIiaNasGffu3ctRdm73Y+jQoWzdupXPPvuM3bt3s2zZMrp27UpMTEy+/SuEEKJsKy3jashastqsWTMCAwP55ptv2L59Oz179mT8+PFMnz49R/pPPvmEGzdusGzZMpYuXUpISAi9evUiMzNTm2b16tV069YNGxsbfvvtNzZs2EDFihXp3r17jkAbQP/+/alduzYbN25kyZIlALz++ussWLCA119/nW3btvHSSy/Rr18/nUCWi4sLvXv3ZsmSJTrlQ9YYoVq1avTr1y/fPsht3FjQNhTk7/ns2bMZNWoUDRs2ZPPmzXz33XecP3+eVq1aERISkm/98tOzZ0++/PJLIGtcmT0+7tmzZ67pFUWhb9++zJs3j6FDh/L3338zceJEfvvtNzp37qz9MD9bQd4/CSEeQxGinFm+fLkCKKdOnVIOHDigAEpgYKCiKIrSrFkzZcSIEYqiKErDhg2VDh06aJ/Xo0cPBVBSUlIKXJahoaHSuXPnfNO99tpripubm/b7rl27KqNHj1bs7OyU3377TVEURTl69KgCKLt379amc3Z2VszMzJQbN25oryUnJysVK1ZUxowZo702ZswYxcrKSiedoijKvHnzFEC5ePGioiiKEhoaqgBKrVq1lLS0NJ209erVUxo3bqykp6frXH/xxReVqlWrKpmZmfm2M1tmZqaSnp6uzJgxQ6lUqZKi0Wgem/7zzz9XHv111KFDB537k113T09PJSMjQ3v95MmTCqCsXbu2SNqyZMkSBVA2bNigc/2rr77KcX86dOigNGzY8LFty/bo6y1b9mu0ffv2OR7LrV8U5b/XeGhoqKIoihIeHq4YGRkp77zzjk66hIQEpUqVKsrAgQMfW7fCvn6K8h5kt2XYsGE66e7fv6+YmpoqgwYN0rnu5+enADp9ee3aNcXAwED59ttvtdeSk5OVSpUqKa+//vpj264oigLk+bVq1ap8n/+wjIwMJT09XenSpYvSr18/7fXsvqtWrZqSnJysvR4fH69UrFhR6dq1q/Za9n1/7733dPJes2aNAiirV69WFOXp7ntGRoaSmJioWFpaKt999532el73Q1EUxcrKSpkwYUIBe0IIIUR5UBrH1d27d1eqV6+uxMXF6Vx/++23FTMzM+X+/fuKovw3xnrhhRd00m3YsEEBFD8/P0VRFCUpKUmpWLGi0qtXL510mZmZSqNGjZTmzZtrr2X/jf7ss8900l68eFEBlI8++kjn+tq1axVAGT58uPZadr22bNmivXb79m3FyMhImT59+mPbnte4sTBtyO/v+YMHDxRzc/Mc/RYeHq6YmpoqQ4YM0V7LbawKKJ9//nmOfJ2dnXX6YePGjQqgHDhwIEfa4cOHK87Oztrvd+7cqQDK119/rZNu/fr1CqAsXbpUp5yCvH8SQuRNZhSKcq1Dhw7UqlWLX3/9lQsXLnDq1KkCzS4qqIyMjFw/ZXxUly5duH79OqGhoaSkpODr60uPHj3o1KkTe/bsAbJmGZqamtK2bVud53p7e1OzZk3t92ZmZtSpU0dnyeD27dvp1KkT1apV05kN9fzzzwNZG00/rHfv3jp7wly9epXLly9r99p7OI8XXniBiIiIXJdoPGz//v107doVW1tbDA0NMTY25rPPPiMmJoaoqKh8+6igevbsiaGhofZ7Ly8vAG1/PG1b9u/fj6WlJQMGDNC5nr1UoiD3+0m89NJLT/zcXbt2kZGRwbBhw3Taa2ZmRocOHfJcEp2tsK+f4rgHj7b/+PHjpKamMnDgQJ3rLVu2zLEUxc3NjRdffJHFixdrZwD+/vvvxMTE8Pbbbz+27dkGDhzIqVOncny98MIL+T53yZIl+Pj4YGZmhpGREcbGxuzbty/X5Tn9+/fHzMxM+721tTW9evXi8OHDOWYWPLr35cCBAzEyMtJuFVCY+56YmMhHH31E7dq1MTIywsjICCsrK5KSknKtZ26vx+bNm7NixQpmzZrF8ePHdWY2CiGEKP9Kw7gLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1300x420 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"response = np.load(RESPONSE)\n",
|
||||
"centre = response['table_centre']\n",
|
||||
"figure, axes = plt.subplots(1, 2, figsize=(13, 4.2))\n",
|
||||
"for curve, colour, label in ((correction, COLOURS['grid corrected'], 'core of E_pred (used)'),\n",
|
||||
" (correction_mean, '#c0392b', 'mean of E_pred')):\n",
|
||||
" axes[0].plot(curve.grid, curve.g_grid - curve.grid, color=colour, lw=1.5, label=label)\n",
|
||||
"for name in LINES:\n",
|
||||
" axes[0].axvline(line_centroid(name), color='k', lw=.5, ls=':')\n",
|
||||
"axes[0].axhline(0, color='k', lw=.6); axes[0].set_ylim(-0.6, 0.3)\n",
|
||||
"axes[0].set_xlabel('E_true [keV]'); axes[0].set_ylabel('g(E) - E [keV]')\n",
|
||||
"axes[0].set_title('MC: where a line of true energy E appears'); axes[0].legend(fontsize=8)\n",
|
||||
"axes[0].grid(alpha=.3)\n",
|
||||
"axes[1].plot(centre, response['table_core_sigma'], 'k.', ms=3, label='core sigma, raw')\n",
|
||||
"axes[1].plot(correction.grid, correction.mc_sigma(correction.grid) / correction.slope(correction.grid),\n",
|
||||
" color=COLOURS['grid corrected'], lw=1.2, label=\"core sigma / g' (true keV)\")\n",
|
||||
"axes[1].set_ylim(0, 0.4); axes[1].set_xlabel('E_true [keV]'); axes[1].set_ylabel('keV')\n",
|
||||
"axes[1].set_title('MC: energy resolution'); axes[1].legend(fontsize=8); axes[1].grid(alpha=.3)\n",
|
||||
"figure.tight_layout()\n",
|
||||
"for name in LINES:\n",
|
||||
" e = line_centroid(name)\n",
|
||||
" print(f\"{name}: g - E = {(correction.forward(np.array([e]))[0] - e)*1000:+.0f} meV, \"\n",
|
||||
" f\"g' = {correction.slope(e):.2f}, MC core sigma {correction.mc_sigma(e):.3f} keV\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "2d694291",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 2. Spectra\n",
|
||||
"\n",
|
||||
"Per frame, 50 eV bins; grey = outside the 3-30 keV training range."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "88a7f95b",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-19T09:10:40.639432Z",
|
||||
"iopub.status.busy": "2026-09-19T09:10:40.639337Z",
|
||||
"iopub.status.idle": "2026-09-19T09:10:49.511881Z",
|
||||
"shell.execute_reply": "2026-09-19T09:10:49.511595Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1400x850 with 2 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"histograms = {name: np.histogram(values, EDGES)[0] for name, values in energies.items()}\n",
|
||||
"figure, axes = plt.subplots(2, 1, figsize=(14, 8.5))\n",
|
||||
"for axis, log in zip(axes, (True, False)):\n",
|
||||
" for name, counts in histograms.items():\n",
|
||||
" axis.plot(CENTRES, counts / frames_of[name], lw=1, color=COLOURS[name], label=name)\n",
|
||||
" for name in LINES:\n",
|
||||
" axis.axvline(line_centroid(name), color='k', lw=.4, ls='--')\n",
|
||||
" axis.axvspan(0, 3, color='0.9'); axis.axvspan(30, 40, color='0.9')\n",
|
||||
" axis.set_xlabel('energy [keV]'); axis.set_ylabel('photons / frame / 50 eV')\n",
|
||||
" axis.grid(alpha=.3)\n",
|
||||
" if log:\n",
|
||||
" axis.set_yscale('log'); axis.set_xlim(2, 33); axis.set_ylim(1e-4, None)\n",
|
||||
" axis.legend(fontsize=9); axis.set_title(RUN)\n",
|
||||
" else:\n",
|
||||
" axis.set_xlim(*SPECTRUM_ZOOM)\n",
|
||||
"figure.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "02b8297f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 3. Line positions and energy resolution\n",
|
||||
"\n",
|
||||
"Grid lines: Gaussian core + a wide Gaussian at the same position (the tails of\n",
|
||||
"section 1) + an erfc low-energy step, on an exp(polynomial) background.\n",
|
||||
"Classical lines: Gaussian + step. Ka is fitted as the tabulated doublet, so the\n",
|
||||
"position is the intensity-weighted centroid. `sigma` is the core width; FWHM is\n",
|
||||
"that of the whole line shape."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "e00064c3",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-19T09:10:49.513200Z",
|
||||
"iopub.status.busy": "2026-09-19T09:10:49.513104Z",
|
||||
"iopub.status.idle": "2026-09-19T09:10:54.511973Z",
|
||||
"shell.execute_reply": "2026-09-19T09:10:54.511727Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
" table | position [keV] | core sigma [keV] | FWHM [keV] | MC sigma\n",
|
||||
" | direct corr. 3x3 | direct corr. 3x3 | grid 3x3 ratio |\n",
|
||||
"Cr_Ka 5.41 | 5.42 5.42 5.46 | 0.245 0.245 0.398 | 0.58 0.94 0.62 | 0.256\n",
|
||||
"Co_Ka 6.93 | 6.95 6.95 6.99 | 0.265 0.264 0.408 | 0.62 0.96 0.65 | 0.264\n",
|
||||
"Cu_Ka 8.04 | 8.08 8.07 8.11 | 0.305 0.305 0.441 | 0.72 1.04 0.69 | 0.267\n",
|
||||
"elastic | 11.99 11.99 12.05 | 0.311 0.312 0.470 | 0.73 1.11 0.66 | 0.279\n",
|
||||
"grid FWHM: direct output\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"fits = {}\n",
|
||||
"for variant, counts in histograms.items():\n",
|
||||
" for group in FIT_GROUPS:\n",
|
||||
" fits[variant, group['label']] = fit_lines(\n",
|
||||
" CENTRES, counts, group['alpha'], group.get('beta'), window=group['window'],\n",
|
||||
" beta_ratio_fixed=group.get('ratio_fixed'),\n",
|
||||
" fit_stretch=group.get('fit_stretch', True), extra_peaks=group.get('extra', ()),\n",
|
||||
" tails=variant != 'classical 3x3')\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def peak(variant, name):\n",
|
||||
" group = next(g for g in FIT_GROUPS\n",
|
||||
" if name in g['alpha'] or name in [e[0] for e in g.get('extra', ())])\n",
|
||||
" return fits[variant, group['label']]['lines'][name]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def fwhm_of(variant, name):\n",
|
||||
" \"\"\"FWHM of the line shape; for the extra peaks (no doublet) from sigma.\"\"\"\n",
|
||||
" line = peak(variant, name)\n",
|
||||
" return line.get('fwhm', 2.3548 * line['sigma'])\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"print(f\"{'':8s} {'table':>6s} | {'position [keV]':^26s} | {'core sigma [keV]':^26s} | \"\n",
|
||||
" f\"{'FWHM [keV]':^20s} | MC sigma\")\n",
|
||||
"print(f\"{'':8s} {'':>6s} | {'direct':>8s} {'corr.':>8s} {'3x3':>8s} | \"\n",
|
||||
" f\"{'direct':>8s} {'corr.':>8s} {'3x3':>8s} | {'grid':>6s} {'3x3':>6s} {'ratio':>6s} |\")\n",
|
||||
"for name in PEAKS:\n",
|
||||
" table = f\"{line_centroid(name):6.2f}\" if name in LINES else f\"{'':6s}\"\n",
|
||||
" positions = [peak(v, name)['mu'] for v in energies]\n",
|
||||
" sigmas = [peak(v, name)['sigma'] for v in energies]\n",
|
||||
" grid_fwhm = fwhm_of('grid direct', name)\n",
|
||||
" classical_fwhm = fwhm_of('classical 3x3', name)\n",
|
||||
" mc = correction.mc_sigma(line_centroid(name)) if name in LINES else \\\n",
|
||||
" correction.mc_sigma(peak('grid corrected', name)['mu'])\n",
|
||||
" print(f\"{name:8s} {table} | \" + ' '.join(f'{p:8.2f}' for p in positions) + ' | ' +\n",
|
||||
" ' '.join(f'{s:8.3f}' for s in sigmas) +\n",
|
||||
" f\" | {grid_fwhm:6.2f} {classical_fwhm:6.2f} {grid_fwhm/classical_fwhm:6.2f} | {mc:.3f}\")\n",
|
||||
"print('grid FWHM: direct output')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "d7c0b45e",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-19T09:10:54.513111Z",
|
||||
"iopub.status.busy": "2026-09-19T09:10:54.513023Z",
|
||||
"iopub.status.idle": "2026-09-19T09:10:55.229598Z",
|
||||
"shell.execute_reply": "2026-09-19T09:10:55.229316Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAABtYAAAJOCAYAAAAj/DNqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzddVxV9xvA8c+lG0RQQcHGDlRsxFbsqbO7c1MXxsL1jG06J7o5nV3bnM6J3cxEFAsDFJvujnvP7w9+uxsmKnCJ5/168dJ74nuec8Tz3HO+pVIURUEIIYQQQgghhBBCCCGEEEII8Vx6ug5ACCGEEEIIIYQQQgghhBBCiMJAKtaEEEIIIYQQQgghhBBCCCGEyAGpWBNCCCGEEEIIIYQQQgghhBAiB6RiTQghhBBCCCGEEEIIIYQQQogckIo1IYQQQgghhBBCCCGEEEIIIXJAKtaEEEIIIYQQQgghhBBCCCGEyAGpWBNCCCGEEEIIIYQQQgghhBAiB6RiTQghhBBCCCGEEEIIIYQQQogckIo1IYQQQgghhBBCCCGEEEIIIXJAKtaEeIynpyfLli175vpevXrxySef5Li8/27v4+NDuXLlXjNCIYQQQgghhBD/kGe4fx09ehQbG5s8KXvChAnMnDkzT8oWQoiiokKFCuzYsSPPys+te/GaNWuoX7/+6wekA5988gm9evXKk7Jr1arFrl278qRsUbRIxZoQj9mzZw+TJk3Kk7Ld3d158OBBnpR9584dVCoVsbGxL73vX3/9RatWrbC0tKRkyZI0btyYH3/88YX7nThxIlsS/vvvv/H09KREiRLY2NhQr149FixYQHp6eo5jGTt2LIsXLwZArVbz7bffUrt2bczNzXFwcKBz584cOnToZU8ReDLxJicn4+npSatWrYiLi3ulMoUQIq/IA5kQQgiRM8XxGS6vPe2l5Y8//sj8+fN1E5AQQggg/+7FU6dOxcnJCSsrK8qWLcu0adNy/H5vz5491KlThxIlSmBra0uHDh24fPlyHkf88lq3bq19B/mPq1ev0q1bN90EJAoVqVgT4v8URUGtVus0hszMzHw/5vLlyxk+fDhjx47lwYMHREZGsmzZsme2zvhvjH/99Rfdu3cHYNeuXXh6etKpUycCAwOJjY1l69atBAQEEBISkqNYFEXB29tbW+bgwYP55Zdf8PLyIjo6mrt37zJlyhS2bdv2mmcNsbGxdOjQAT09Pfbt24e1tfVrlymEEIVJcXkge51GGl9++SXTpk3Tfl69ejWNGjXCwsKC0qVL4+HhwW+//fZS8VStWhV/f38AoqKieOuttyhfvjwWFhZUqFCBESNGcPPmzZcq8x+PPxjeunWLSpUq8fbbb6MoyiuVKYQQBVlxfYYTQggh8tqkSZO4fv068fHx+Pv7c/HiRRYsWJCjfevXr8/+/fuJiYkhPDycrl275lkPMyF0RSrWRJH24MEDOnTogJWVFQ0bNuSrr76iQoUK2vUVKlTg66+/pmnTppiZmREQEPDES6lt27ZRpUoVrK2tGTt27AsfnJ63/ePDcrRu3Zr333+fjh07Ym5uzp49e0hMTGTKlCk4OztTqlQphg0blq03VWBgID169MDe3h5bW1t69+4NQOPGjQEoV64cFhYWbNy48YXXJyEhgZkzZ7JkyRKGDh2KtbU1KpWKRo0aaSvW/ol5+fLlODs706xZM+3+O3fupEePHiiKwltvvcXMmTOZNm0adnZ2AFSvXp01a9ZQvnx5AM6dO0eLFi2wsbGhZs2abN68OVs8vr6+lChRgsqVK3Ps2DG2b9/Ozp078fDwwNjYGCMjI7p166Yd5mXEiBHZXnjGxsaiUqm4c+fOc887NDQUDw8PnJ2d2bFjB6ampi+8VkIIIV6Nrh/IXraRxrMakMyaNYuPP/6YuXPnEhYWxqNHj/j000/Zvn17jmO5fv06aWlp1K9fn7i4OJo3b87du3fZt2+f9vo0adKEPXv2vNQ5Ps2lS5do2bIlw4YN4/vvv0elUr12mUIIkR/kGe7FwsPDGTx4MI6Ojjg6OjJt2jTS0tKeuu3GjRupXbs2lpaWODs789FHH2kbWyiKwsyZMylTpgxWVla4uLiwa9cuduzYwVdffcWuXbuwsLDAwsICePL561nnJYQQRV18fLz2vm9lZYWbmxv3799/Yrt79+7RoUMH7O3tKVGiBF27ds32zurAgQPUrVsXS0tLSpcuzcSJEwFIS0tj1KhR2NnZYW1tTe3atfH19QVe7l48ZMgQHB0dtTn1yJEjOT7HGjVqYG5urv2sp6dHYGAgAPfv38fOzo4DBw4AkJ6eToMGDfjss88AcHBwwMHBAcjKNfr6+ty9e5eMjIwcH//8+fO0adMGW1tbqlSpws8///zMbd9//33Kly+PpaUlNWvWzNb4MTo6mjfeeANbW1tsbGxo2LAhd+/e5Z133sHHx4eZM2diYWGBp6cn8OTIMQcOHKBJkybY2Njg4ODA119/neNzEEWbVKyJIm3QoEGUL1+esLAwNm/ezKpVq57YZs2aNaxdu5bExESqVauWbV1gYCCDBg1i0aJFREVF0bBhQ/bu3fvM473s9v8c/4svviAxMZH27dszatQooqOjuXTpEsHBwWRkZDBlyhQAkpKSaN++PbVr1+bOnTuEhoYydepUAM6ePQtkPYgmJiYyePBgAOrWrcumTZueeuxTp06RlJREv379nhtjQkICFy9e5Pr16xw7dgyA27dvExsbS6NGjQgMDCQ4OJiBAwc+s4zY2Fg6d+7MgAEDiIiIYPny5YwdO5YTJ05ot/nrr7/o0aMHAPv27aNx48ZUrlz5ubG9rIcPH9KyZUuaN2/Oxo0bMTQ0zNXyhRDiZcgDWd4+kOWkkcYnn3xCt27dmDhxIra2ttrhMcPCwrh58yatWrXi9u3bfPPNN2zatInu3btjbm6Ovr4+rVu3zpZjN2zYQI0aNbCxsaFly5ZcuHAhWzw7d+7UVtQtXrwYlUrFtm3bqF69Onp6etjY2DBx4kTefvtt4MmHuh07dmR7ufwsJ0+epE2bNsyZM+el5hQSQoiCQJ7hnv8MpygKPXr0oEyZMgQFBXH58mUuXrzIF1988dTtbW1t+eOPP4iPj2fnzp2sWLFCW/aBAwfYtGkT58+fJz4+noMHD+Li4kKvXr2YM2cO3bp1IzExkcTExCfKfd55CSFEUTdixAiCgoI4ffo0sbGxrFix4qmNtjUaDTNmzOD+/fvcvXsXMzMzxo4dq10/fPhw3nvvPRISErh9+zZDhw4FYO3atVy8eJGgoCBiY2P5448/KFOmzBPlv+he3K5dO65du0ZUVBQDBgygb9++JCQk5Pg8582bh6WlJaVKleLixYvasp2cnFixYgXDhg0jPDxcWzn1wQcfaPe9d+8eNjY2mJiY8PbbbzN79mztO7h/1t27d++pxw0NDaVDhw5MnDiRiIgIduzYwdy5c5856ki9evXw9fUlNjaWjz/+mKFDhxIcHAzAN998Q2ZmJg8ePCAqKopVq1ZhaWnJt99+i7u7O/PnzycxMfGpjRsvXLhAz549ef/994mIiOD69eu0adMmx9dPFG1SsSaKrPv37+Pj48O8efMwNTXFxcWFCRMmPLHdxIkTqVatGvr6+hgZGWVbt2XLFtq1a0f37t0xMDBgwoQJVK1a9ZnHfNntIevBsXHjxqhUKhITE9m2bRtLly7FxsYGc3NzPvvsM7Zu3YparWbXrl0YGhry5ZdfYm5ujpGR0Qtv6JcuXWLQoEFPXRcREYG9vf0T5/04jUbDvHnzMDMzw8zMDMh6OditWzdUKhUREREAlC1b9plleHt7Y29vz9SpUzE0NMTDw4NBgwaxdu1a7Tb/7RkQERHx3PJe1Y0bN7h//z6jRo1CT09ugUII3ZIHsrx9IMtpI429e/fSpEkTwsPD+fzzz4GsIY47deqEoaEhBw8exMHBAXd392eW4ePjw8SJE/npp5+IiIigb9++dOrUKVuPhccbkLz55psYGBjk4Arm3OHDh/H09GTx4sXyglMIUejIM1yW5z3DnTt3jsDAQBYuXIiZmRklS5Zkzpw5z6yI8/T0xMXFBZVKRf369Rk4cCBHjx4FwNDQkNTUVK5evUpGRgbOzs64uLg8N7Z/vMp5CSFEURAWFsb27dtZsWIFjo6O6Onp4erqqh296b8qVKiAp6cnJiYmWFlZ8cEHH3D8+HE0Gg2QdR8OCgoiIiICc3Nzmjdvrl2ekJDAtWvXUBQFFxcXnJycnij/RffikSNHYm1tjaGhIe+99x4ajYZLly7l+FxnzZpFQkICAQEBTJgwIduzZO/evenRowft27dn3bp1bNy4EX19fe16Z2dnYmNjiY2NZcmSJTRq1OiJdc7Ozk897vr162nVqhX9+vVDX1+f2rVrM3LkyGfmusGDB1OqVCn09fUZMGAA1atX5+TJk9prGRUVRWBgIPr6+tSvXx9bW9scnf+KFSsYMGAAffr0wdDQEGtra5o2bZqjfUXRJ2+VRZH16NEjTExMsiW2p92wn3UT/6eMf4Yx/Mfjn19n+8ePf+fOHTQaDZUqVcLGxgYbGxvc3NzQ09MjNDSUu3fvUrly5VwbzsnOzo7IyMgXznVjaWmZbfgT+HcYyH/KgazeYM/y4MGDJ1rZV6pUSTsR+L179wgJCdEmKDs7u+eW96ratm3L3Llz6dixo7aFqBBC6II8kGXJyweynDbSqF27NiNGjMDAwEDbgORlG3usW7eOIUOG0KpVKwwNDZk2bRolSpTA29sbyJpP7cqVK7Ru3fqlYntZR48epVSpUnTp0iXXyxZCiLwmz3AvdufOHWJjY7VDWtnY2NC3b1/CwsKeuv2+ffto3ry5tvf6jz/+SGRkJABt2rTh008/5aOPPsLOzo4+ffpoW/i/SG6flxBCFBZ3797F2Nj4ubnoHxEREQwaNEg753SrVq1IT0/XNlLcvn07V65coVq1ariLine truncated
|
||||
"text/plain": [
|
||||
"<Figure size 1760x600 with 8 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"shown = ('grid direct', 'classical 3x3')\n",
|
||||
"figure, axes = plt.subplots(2, len(FIT_GROUPS) * 2, figsize=(4.4 * len(FIT_GROUPS) * 2, 6),\n",
|
||||
" gridspec_kw=dict(height_ratios=[3, 1]), squeeze=False)\n",
|
||||
"for column, (group, variant) in enumerate((g, v) for g in FIT_GROUPS for v in shown):\n",
|
||||
" fit = fits[variant, group['label']]\n",
|
||||
" x = fit['centres']\n",
|
||||
" axes[0, column].plot(x, fit['counts'], 'k.', ms=2.5)\n",
|
||||
" axes[0, column].plot(x, fit['model'](x), color=COLOURS[variant], lw=1.3)\n",
|
||||
" for part, curve in fit['components'](x).items():\n",
|
||||
" axes[0, column].plot(x, curve, lw=.7, ls='--', label=part)\n",
|
||||
" axes[0, column].set_yscale('log')\n",
|
||||
" axes[0, column].set_ylim(max(fit['counts'].min() * 0.5, 1), fit['counts'].max() * 2)\n",
|
||||
" axes[0, column].set_title(f\"{variant}: {group['label']}\", fontsize=9)\n",
|
||||
" axes[0, column].legend(fontsize=6)\n",
|
||||
" axes[1, column].plot(x, (fit['counts'] - fit['model'](x)) / np.sqrt(np.maximum(fit['counts'], 1)),\n",
|
||||
" '.', ms=2.5, color=COLOURS[variant])\n",
|
||||
" axes[1, column].axhline(0, color='k', lw=.6)\n",
|
||||
" axes[1, column].set_xlabel('energy [keV]'); axes[1, column].set_ylabel('pull')\n",
|
||||
"figure.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "48f4f57f",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-19T09:10:55.230821Z",
|
||||
"iopub.status.busy": "2026-09-19T09:10:55.230692Z",
|
||||
"iopub.status.idle": "2026-09-19T09:10:55.331040Z",
|
||||
"shell.execute_reply": "2026-09-19T09:10:55.330825Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 750x440 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"figure, axis = plt.subplots(figsize=(7.5, 4.4))\n",
|
||||
"for offset, variant in zip((-0.08, 0.0, 0.08), energies):\n",
|
||||
" axis.errorbar([line_centroid(n) + offset for n in LINES],\n",
|
||||
" [peak(variant, n)['sigma'] for n in LINES],\n",
|
||||
" [peak(variant, n)['sigma_err'] for n in LINES],\n",
|
||||
" fmt='o', ms=5, capsize=3, color=COLOURS[variant], label=variant)\n",
|
||||
"e = np.linspace(min(line_centroid(n) for n in LINES) - 1, max(line_centroid(n) for n in LINES) + 1, 200)\n",
|
||||
"e = e[(e >= 5) & (e <= 30)]\n",
|
||||
"axis.plot(e, correction.mc_sigma(e), 'k--', lw=1, label='MC core sigma (raw)')\n",
|
||||
"axis.plot(e, correction.mc_sigma(e) / correction.slope(e), 'k:', lw=1, label=\"MC / g' (true keV)\")\n",
|
||||
"axis.set_xlabel('line energy [keV]'); axis.set_ylabel('core sigma [keV]'); axis.set_ylim(0, None)\n",
|
||||
"axis.set_title('energy resolution'); axis.legend(fontsize=8); axis.grid(alpha=.3)\n",
|
||||
"figure.tight_layout()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "32c28598",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 4. Reconstruction efficiency\n",
|
||||
"\n",
|
||||
"Without truth, three handles on the 10 000 frames of the classical reference:\n",
|
||||
"\n",
|
||||
"* **isolated photons**: classical clusters with no other cluster within 4 px\n",
|
||||
" that have a grid photon within 1.5 px. Above 5 keV the 2.5 keV classical\n",
|
||||
" threshold finds every isolated photon, so this is the absolute efficiency.\n",
|
||||
" The MC equivalent is photons with no neighbour within 4 px.\n",
|
||||
"* **pile-up**: classical clusters holding two or more grid photons within 2 px.\n",
|
||||
"* **energy balance**: summed reconstructed energy / deposited energy per frame\n",
|
||||
" (calibrated frame minus its baseline)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "045ab180",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-19T09:10:55.332205Z",
|
||||
"iopub.status.busy": "2026-09-19T09:10:55.332119Z",
|
||||
"iopub.status.idle": "2026-09-19T09:10:56.819582Z",
|
||||
"shell.execute_reply": "2026-09-19T09:10:56.819355Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"isolated photons >= 5 keV found: 99.99 % (3-5 keV: 100.0 %; MC: 99.96 %)\n",
|
||||
"grid / classical photon count: 1.067\n",
|
||||
"classical clusters with >= 2 grid photons: 10.2 % (Poisson, second photon within 2 px: 15.0 %)\n",
|
||||
"energy balance: grid 0.9961, classical 0.9991\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<Figure size 750x420 with 1 Axes>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"match = reference['classical_match']\n",
|
||||
"found = match >= 0\n",
|
||||
"isolated = reference['isolation_classical'] > 4.0\n",
|
||||
"above5 = classical[:, 3] >= 5\n",
|
||||
"edges_e = np.arange(2.5, 30.01, 0.5)\n",
|
||||
"which = np.digitize(classical[:, 3], edges_e) - 1\n",
|
||||
"fraction = np.array([found[isolated & (which == i)].mean() if (isolated & (which == i)).sum() > 200\n",
|
||||
" else np.nan for i in range(len(edges_e) - 1)])\n",
|
||||
"\n",
|
||||
"mc = json.load(open(EXPERIMENT / 'eval_summary.json'))['1%']['pair']\n",
|
||||
"far = [i for i, edge in enumerate(mc['edges']) if edge >= 4.0]\n",
|
||||
"mc_isolated = sum(mc['n_match'][i] for i in far) / sum(mc['n_true'][i] for i in far)\n",
|
||||
"\n",
|
||||
"figure, axis = plt.subplots(figsize=(7.5, 4.2))\n",
|
||||
"axis.plot(0.5 * (edges_e[1:] + edges_e[:-1]), fraction * 100, 'o-', ms=3,\n",
|
||||
" color=COLOURS['grid direct'], label='isolated classical clusters found by the grid')\n",
|
||||
"axis.axhline(mc_isolated * 100, color='k', ls='--', lw=1, label='MC, isolated photons, 1 %')\n",
|
||||
"axis.axvspan(0, 3, color='0.9'); axis.set_ylim(90, 100.5); axis.set_xlim(2.5, 30)\n",
|
||||
"axis.set_xlabel('classical 3x3 energy [keV]'); axis.set_ylabel('%')\n",
|
||||
"axis.set_title('detection efficiency'); axis.legend(fontsize=8); axis.grid(alpha=.3)\n",
|
||||
"figure.tight_layout()\n",
|
||||
"\n",
|
||||
"multiplicity = reference['grid_per_classical']\n",
|
||||
"occupancy = summary['occupancy_valid_region']\n",
|
||||
"balance = reference['balance'][:, 1].sum()\n",
|
||||
"low = (classical[:, 3] >= 3) & ~above5\n",
|
||||
"print(f\"isolated photons >= 5 keV found: {found[isolated & above5].mean()*100:.2f} % \"\n",
|
||||
" f\"(3-5 keV: {found[isolated & low].mean()*100:.1f} %; MC: {mc_isolated*100:.2f} %)\")\n",
|
||||
"print(f\"grid / classical photon count: {len(grid_subset) / len(classical):.3f}\")\n",
|
||||
"print(f\"classical clusters with >= 2 grid photons: {(multiplicity >= 2).mean()*100:.1f} % \"\n",
|
||||
" f\"(Poisson, second photon within 2 px: {(1 - np.exp(-occupancy * np.pi * 4))*100:.1f} %)\")\n",
|
||||
"print(f\"energy balance: grid {grid_subset[:, 3].sum() / balance:.4f}, \"\n",
|
||||
" f\"classical {classical[:, 3].sum() / balance:.4f}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4e5818b8",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Conclusions\n",
|
||||
"\n",
|
||||
"* **Lines.** The grid separates Cr, Co and Cu Ka cleanly; the classical 3x3\n",
|
||||
" sum shows Cu Ka only as a shoulder. Grid positions within 0.04 keV of the\n",
|
||||
" tables, classical 0.05-0.07 keV high (the LUT reads ~0.9 % high at\n",
|
||||
" 5-8 keV). The pile-up continuum at 13-25 keV is 5-10x lower than in the\n",
|
||||
" classical spectrum.\n",
|
||||
"* **Cr Ka and the training range.** With Cr Ka 2.4 keV inside the 3-30 keV\n",
|
||||
" range, the model puts it at +0.01 keV with a 0.245 keV core (MC 0.256)\n",
|
||||
" straight away. The previous 5-30 keV model, whose edge sat 0.4 keV below the\n",
|
||||
" line, gave +0.03 keV with a compressed 0.18 keV core, and its MC correction\n",
|
||||
" overshot. Here the correction changes nothing (<= 7 meV).\n",
|
||||
"* **Energy resolution.** FWHM 0.58 / 0.62 / 0.72 keV for Cr / Co / Cu Ka and\n",
|
||||
" 0.73 keV for the elastic line, against 0.94 / 0.96 / 1.04 / 1.11 keV for the\n",
|
||||
" classical sum: 31-38 % narrower. The core widths agree with the MC within\n",
|
||||
" +-5 % for Cr and Co; Cu and the elastic line are 12-14 % wider.\n",
|
||||
"* **Efficiency.** 99.99 % of the isolated photons above 5 keV and 100 % at\n",
|
||||
" 3-5 keV (MC 99.96 %). The grid finds 6.7 % more photons than the classical\n",
|
||||
" finder (pile-up), and the energy balance is 0.996."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "403d0ea6",
|
||||
"metadata": {
|
||||
"execution": {
|
||||
"iopub.execute_input": "2026-09-19T09:10:56.820785Z",
|
||||
"iopub.status.busy": "2026-09-19T09:10:56.820668Z",
|
||||
"iopub.status.idle": "2026-09-19T09:10:56.892665Z",
|
||||
"shell.execute_reply": "2026-09-19T09:10:56.892382Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"output = dict(\n",
|
||||
" run=RUN, epoch=summary['epoch'], n_frames=n_frames,\n",
|
||||
" photons_per_frame=summary['photons_per_frame'], occupancy=occupancy,\n",
|
||||
" lines={name: {variant: dict(mu=float(peak(variant, name)['mu']),\n",
|
||||
" sigma=float(peak(variant, name)['sigma']),\n",
|
||||
" fwhm=float(fwhm_of(variant, name)))\n",
|
||||
" for variant in energies}\n",
|
||||
" for name in PEAKS},\n",
|
||||
" efficiency_isolated_above5keV=float(found[isolated & above5].mean()),\n",
|
||||
" efficiency_isolated_mc=mc_isolated,\n",
|
||||
" grid_over_classical_count=len(grid_subset) / len(classical),\n",
|
||||
" energy_balance_grid=float(grid_subset[:, 3].sum() / balance),\n",
|
||||
")\n",
|
||||
"with open(GRID / RUN / 'xrf_energy_analysis.json', 'w') as handle:\n",
|
||||
" json.dump(output, handle, indent=1)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "pytorch_nightly",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.18"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,635 @@
|
||||
# GridBased
|
||||
|
||||
Grid-based X-ray reconstruction for MÖNCH. A fully-convolutional network reads a
|
||||
calibrated frame and predicts, for **every pixel cell**, whether a photon
|
||||
converted there, where inside the cell, and with what energy. The number of
|
||||
photons in a frame is an output of the model, so one set of weights covers any
|
||||
multiplicity and any flux, and those same weights run on a 32×32 training frame
|
||||
or on a full detector frame.
|
||||
|
||||
Design rationale, work-package split and open questions:
|
||||
[`docs/WORKFLOW_DESIGN.md`](docs/WORKFLOW_DESIGN.md).
|
||||
|
||||
**Stage 1: 12 keV monochromatic, MOENCH040 @150 V** — the point where this
|
||||
workflow can be compared head-to-head with the published cluster-based results
|
||||
(σ = 0.8 µm on MC, MTF50 = 160 lp/mm at DanMAX). Done: gate G2 on MC, knife
|
||||
edge at four flux points.
|
||||
|
||||
**Stage 2 (current): polychromatic 3–30 keV, MOENCH014 @150 V** — per-photon
|
||||
energy from the same network. Done: α(E,t)/β(E,t) charge LUT, MC training and
|
||||
evaluation, XRF lines at 2603 MaxIV (energy resolution and efficiency against the
|
||||
classical 3×3 sum), and a scan of network sizes. Default model:
|
||||
`Results/260919_poly3to30keV_Moench014_c96_00`, `[32, 64, 96, 96]`.
|
||||
|
||||
---
|
||||
|
||||
## Pipeline
|
||||
|
||||
```
|
||||
McGeneration single-photon stamps (12 keV: existing, 10 M events, noiseless 5×5)
|
||||
or α(E,t)/β(E,t) charge-cloud LUT (3–30 keV: scripts/01_build_charge_lut.py)
|
||||
│ scripts/02_generate_frames.py ← superpose stamps / sample clouds + noise
|
||||
▼
|
||||
MC frames + truth photon list (HDF5)
|
||||
│ scripts/03_train.py ← fully-convolutional GridNet
|
||||
▼
|
||||
model checkpoint
|
||||
│ scripts/04_evaluate.py ← efficiency/purity/RMS vs occupancy
|
||||
│ scripts/07_energy_response.py ← MC line position g(E) and width (poly)
|
||||
│ scripts/05_infer_measurement.py ← raw ADU → photon list → image
|
||||
▼
|
||||
benchmark plots, reconstructed images
|
||||
```
|
||||
|
||||
## Conventions
|
||||
|
||||
* Pixel `(row r, col c)` covers `x ∈ [c, c+1)`, `y ∈ [r, r+1)`. A photon position
|
||||
is a float in `[0, S)`; its cell is `(⌊y⌋, ⌊x⌋)` and its in-cell offset is
|
||||
`(x−c−0.5, y−r−0.5) ∈ [−0.5, 0.5]`.
|
||||
* Energies are keV throughout; positions are pixels (25 µm) unless a name says `_um`.
|
||||
* **Duplicate suppression works in position space.** Every cell predicts a
|
||||
physical position, so two cells that point at the same place — within
|
||||
`eval.merge_distance` (0.1 px in the current configs) — are merged and the
|
||||
stronger one kept, while two
|
||||
cells that point at different places both survive. Predictions that merge are
|
||||
always less than 1 px apart and therefore in adjacent cells, so comparing the 8
|
||||
neighbours is enough and the decode costs the same as a max-pool.
|
||||
* **Receptive-field radius R = number of 3×3 conv layers = the halo.** Cells
|
||||
within R of a frame border are supervised nowhere and reported nowhere, so the
|
||||
zero padding stays invisible to everything that is used.
|
||||
`scripts/00_selftest.py` checks that a 32×32 frame and the same content embedded
|
||||
in a larger frame give bit-identical predictions inside the halo — that is what
|
||||
makes train-small / infer-large exact — and that R is tight, the ring at R−1
|
||||
already differing.
|
||||
* **One photon per cell sets a known ceiling.** For a Poisson field of occupancy
|
||||
λ, a single slot per 25 µm cell can represent a fraction
|
||||
`(1−e^−λ)/λ ≈ 1 − λ/2` of the photons: 99.5 % at 1 %, 97.5 % at 5 %, 95.2 % at
|
||||
10 %, 90.6 % at 20 %, 78.7 % at 50 %. The generator reports the loss per shard
|
||||
as `n_same_cell`, and it follows the formula to a few per mille. The ceiling is
|
||||
not a hard bound on the *measured* efficiency: the offset channels are unbounded,
|
||||
so a cell can report a position inside its neighbour.
|
||||
|
||||
## Data layout
|
||||
|
||||
One HDF5 file per shard:
|
||||
|
||||
| dataset | shape | meaning |
|
||||
|---|---|---|
|
||||
| `frames` | (N, S, S) f4 | calibrated frame, keV |
|
||||
| `photons` | (M, 4) f4 | `x, y, E[keV], z[µm]`, frame coordinates |
|
||||
| `frame_ptr` | (N+1,) i8 | photons of frame *i* = `photons[ptr[i]:ptr[i+1]]` |
|
||||
| `occupancy` | (N,) f4 | occupancy each frame was thrown at |
|
||||
|
||||
Splits draw from **disjoint stamp files** (train 0–11, val 12–13,
|
||||
test/eval_scan 14–15), so every single-photon event belongs to exactly one split.
|
||||
|
||||
## Running
|
||||
|
||||
Training, evaluation and inference need an environment with PyTorch
|
||||
(`conda activate pytorch_nightly`); generation needs numpy/h5py/omegaconf.
|
||||
|
||||
```bash
|
||||
cd /home/xie_x1/MLXID/GridBased
|
||||
|
||||
# 0. self-tests (coordinates, D4, translation equivariance, position-space merging)
|
||||
python scripts/00_selftest.py
|
||||
|
||||
# 1. generate MC frames
|
||||
python scripts/02_generate_frames.py --config Configs/generate_frames_12keV.yaml
|
||||
# subsets / quick check:
|
||||
python scripts/02_generate_frames.py --config Configs/generate_frames_12keV.yaml --splits eval_scan
|
||||
python scripts/02_generate_frames.py --config Configs/generate_frames_12keV.yaml --smoke
|
||||
|
||||
# 2. train (-u keeps progress live when the output is redirected)
|
||||
python -u scripts/03_train.py --config Configs/train_grid_12keV.yaml
|
||||
python scripts/03_train.py --config Configs/train_grid_12keV.yaml --epochs 3 --tag smoke
|
||||
|
||||
# 3. evaluate the occupancy scan (0.5 / 1 / 2 / 5 / 10 / 20 / 50 %)
|
||||
python scripts/04_evaluate.py --checkpoint Results/<exp>/Models/best.pth
|
||||
|
||||
# 4. run over measured data
|
||||
python scripts/05_infer_measurement.py --config Configs/infer_measurement_12keV.yaml \
|
||||
--run Edge_3filters_pos0_12keV
|
||||
|
||||
# polychromatic 3-30 keV, MOENCH014: charge LUT (+ its validation), frames, training
|
||||
python scripts/01_build_charge_lut.py --config Configs/charge_lut_Moench014_3to30keV.yaml
|
||||
python scripts/01b_validate_charge_lut.py --lut data/charge_lut_Moench014_150V_3to30keV.npz \
|
||||
--outdir Results/charge_lut_3to30keV
|
||||
python scripts/02_generate_frames.py --config Configs/generate_frames_poly3to30keV_Moench014.yaml
|
||||
python -u scripts/03_train.py --config Configs/train_grid_poly3to30keV_Moench014_c96.yaml
|
||||
python scripts/04_evaluate.py --checkpoint Results/<poly exp>/Models/best.pth
|
||||
# MC energy response (line position g(E), core width, efficiency) -> energy_response.npz
|
||||
python scripts/07_energy_response.py --checkpoint Results/<poly exp>/Models/best.pth
|
||||
# an XRF run, with its photon list for Notebooks/XRF_*.ipynb
|
||||
python scripts/05_infer_measurement.py --config Configs/infer_measurement_poly_Moench014.yaml \
|
||||
--run AgMo_1_factor_10 --save-photons
|
||||
# the whole chain for several network sizes, unattended, with a comparison report
|
||||
# (resumable: finished stages are skipped); see Results/overnight_poly3to30keV/
|
||||
setsid nohup bash scripts/overnight_poly3to30keV.sh \
|
||||
> Results/overnight_poly3to30keV/driver.log 2>&1 < /dev/null &
|
||||
python scripts/08_compare_models.py --out <dir> --model <label> <experiment> <xrf tag> ...
|
||||
```
|
||||
|
||||
The previous 5–30 keV chain is `Configs/charge_lut_Moench014.yaml`,
|
||||
`generate_frames_poly_Moench014.yaml` and `train_grid_poly_Moench014.yaml`.
|
||||
|
||||
Training outputs land in `Results/<YYMMDD>_<name>_<nn>/`: `config.yaml`,
|
||||
`history.json`, `Models/{best,last,E*}.pth`, `Plots/training_curves.png`,
|
||||
`Plots/eval_scan.png`, `Plots/eval_differential.png`, `eval_summary.json`.
|
||||
|
||||
## Knobs that matter
|
||||
|
||||
| where | key | why |
|
||||
|---|---|---|
|
||||
| `Configs/generate_frames_12keV.yaml` | `splits.train.occupancy` | log-uniform 0.2 – 10 % gives one model for all fluxes; `{mode: fixed, value: …}` specialises it to one. |
|
||||
| | `frame.size` | 32 px training frame; the valid region is `(32−2R)²` = 56 % of it. |
|
||||
| | `noise.pixel_keV` | 0.13 keV, which is what the measured runs deliver once the column common mode is removed. |
|
||||
| | `noise.common_mode_*` | available for studying an uncorrected readout; the measurement pipeline removes common mode from the data directly. |
|
||||
| | `edge_augmentation.fraction` | frames containing a sensor boundary, which shrinks the discarded detector border from R to 1 px. |
|
||||
| `Configs/train_grid_12keV.yaml` | `model.channels` | length sets R (and the halo); width sets capacity. |
|
||||
| | `model.norm` | `none` keeps each cell's prediction a function of its own receptive field, which is what makes train-small / infer-large exact; `group` is there if training ever needs stabilising. |
|
||||
| | `loss.w_ene` | 0.1 — at 12 keV the energy head is nearly constant; it earns its weight in the polychromatic extension. |
|
||||
| | `eval.threshold` | the efficiency/purity working point; `04_evaluate.py` sweeps it. |
|
||||
| `Configs/generate_frames_poly3to30keV_Moench014.yaml` | `spectrum.train` | flat 3–30 keV. The energy head is biased within ~0.75 keV of both edges, so the range should reach ~1 keV past the lines of interest; below 3 keV the MC also lacks the entrance-window physics. |
|
||||
| `Configs/train_grid_poly3to30keV_Moench014_*.yaml` | `model.channels` | `[32, 64, 96, 96]` is the default; see "Choosing the size". |
|
||||
| | `loss.w_ene`, `data.energy_scale` | 1.0 and 15 keV: here the energy head carries the spectrum. |
|
||||
| `Configs/infer_measurement_poly_Moench014.yaml` | `calibration.common_mode` | `column_masked` for full-chip or higher-occupancy runs (see Measurement pipeline). |
|
||||
|
||||
## Results — `Results/260831_12keV_Moench040_01`
|
||||
|
||||
2.4 M training frames (61.5 M photons, occupancy log-uniform 0.2–10 %), GridNet
|
||||
with 92 932 parameters, 150 epochs in ~105 min on one RTX 4090; `best.pth` is
|
||||
epoch 135. This is the checkpoint every measurement run in
|
||||
`Configs/infer_measurement_12keV.yaml` is reconstructed with. Evaluated on the
|
||||
fixed-occupancy scan at objectness threshold 0.3, decoding in position space
|
||||
with a 0.1 px merge distance:
|
||||
|
||||
| occupancy | efficiency | purity | RMS | σ68 | sub-pixel non-unif. |
|
||||
|---|---|---|---|---|---|
|
||||
| 0.5 % | 99.66 % | 99.90 % | **0.798 µm** | 0.59 µm | 0.0 % |
|
||||
| 1 % | 99.44 % | 99.86 % | 0.851 µm | 0.61 µm | 2.8 % |
|
||||
| 2 % | 99.04 % | 99.76 % | 0.899 µm | 0.63 µm | 3.6 % |
|
||||
| 5 % | 97.98 % | 99.41 % | 1.145 µm | 0.71 µm | 3.5 % |
|
||||
| 10 % | 96.39 % | 98.27 % | 1.757 µm | 0.94 µm | 6.6 % |
|
||||
| 20 % † | 93.62 % | 94.86 % | 3.352 µm | 1.98 µm | 22.5 % |
|
||||
| 50 % † | 86.74 % | 89.93 % | 6.469 µm | 6.03 µm | 89.7 % |
|
||||
|
||||
† outside the 0.2–10 % training range; the model is extrapolating. Both points
|
||||
were added to `eval_scan` to find where the chain breaks, and it breaks in the
|
||||
sub-pixel phase long before it breaks in efficiency: the excess rms of the phase
|
||||
histogram goes 6.6 % → 22.5 % → 89.7 % at 10 / 20 / 50 %, and the shape is the
|
||||
R1 failure mode the metric was written for. Binned 10x10 over the cell, the
|
||||
centre 2x2 bins sit at 1.20 / 1.43 / 3.52 times flat while the border ring sits
|
||||
at 0.92 / 0.71 / 0.21, so by 50 % the predictions have collapsed onto the cell
|
||||
centres and the sub-pixel information is gone even though 86.7 % of the photons
|
||||
are still "found". See the G2 section for how to read that efficiency.
|
||||
|
||||
For reference, the cluster-based single-photon model reaches σ = 0.8 µm on 12 keV
|
||||
MC and 96–98 % efficiency at 0.7–1.7 % occupancy, with the photon count supplied
|
||||
by the cluster energy. Position resolution matches on the first attempt.
|
||||
|
||||
The predecessor `Results/260830_12keV_Moench040_00` — 120 epochs on a 10x smaller
|
||||
training set, decoded with a 3×3 local maximum — reached 95.5 / 80.8 / 66.5 %
|
||||
efficiency at 1 / 5 / 10 % occupancy. Nearly all of that deficit was the local
|
||||
maximum itself, which silently imposes a 2 px minimum separation between
|
||||
reported photons; `src/decode.py` documents why it was replaced. The offset
|
||||
channels are unbounded, so a cell may report a position outside its own
|
||||
footprint and the position-space decode is not held to the one-photon-per-cell
|
||||
ceiling (~95 % at 10 % occupancy) that bounded the old one. A finer output grid
|
||||
— cells of 25/s µm — remains the lever if the grid itself ever becomes the limit.
|
||||
|
||||
## Baseline comparison — gate G2
|
||||
|
||||
`scripts/06_baseline_comparison.py` runs three chains over the *same* simulated
|
||||
frames and scores them against the same truth with the same matcher (grid model
|
||||
`260831_12keV_Moench040_01/Models/best.pth`, epoch 135, 2000 frames per point,
|
||||
valid region = frame minus the halo). The scan runs to 50 % occupancy, five
|
||||
times past the top of the 0.2–10 % training range, to find where each chain
|
||||
stops working:
|
||||
|
||||
| occupancy | chain | efficiency | purity | RMS | σ68 |
|
||||
|---|---|---|---|---|---|
|
||||
| 0.5 % | grid | 99.61 % | 99.90 % | **0.805 µm** | 0.593 µm |
|
||||
| | cluster + 1/2/3-photon CNNs | 99.64 % | 99.73 % | 0.891 µm | 0.595 µm |
|
||||
| | cluster + eta interpolation | 87.15 % | 99.86 % | 1.430 µm | 1.161 µm |
|
||||
| 1 % | grid | 99.44 % | 99.89 % | 0.860 µm | 0.610 µm |
|
||||
| | cluster + CNNs | 98.26 % | 99.37 % | 1.264 µm | 0.620 µm |
|
||||
| | cluster + eta | 75.49 % | 99.90 % | 1.391 µm | 1.078 µm |
|
||||
| 2 % | grid | 99.01 % | 99.79 % | 0.895 µm | 0.624 µm |
|
||||
| | cluster + CNNs | 91.79 % | 98.00 % | 1.886 µm | 0.675 µm |
|
||||
| | cluster + eta | 58.70 % | 99.84 % | 1.374 µm | 1.038 µm |
|
||||
| 5 % | grid | 97.96 % | 99.41 % | 1.141 µm | 0.710 µm |
|
||||
| | cluster + CNNs | 55.76 % | 92.58 % | 3.522 µm | 0.926 µm |
|
||||
| | cluster + eta | 26.27 % | 99.87 % | 1.608 µm | 1.082 µm |
|
||||
| 10 % | grid | 96.37 % | 98.29 % | 1.771 µm | 0.945 µm |
|
||||
| | cluster + CNNs | 16.12 % | 85.83 % | 5.083 µm | 1.643 µm |
|
||||
| | cluster + eta | 6.99 % | 99.88 % | 2.001 µm | 1.279 µm |
|
||||
| 20 % | grid | 93.56 % | 94.84 % | 3.340 µm | 1.979 µm |
|
||||
| | cluster + CNNs | 0.98 % | (84.85 %) | — | — |
|
||||
| | cluster + eta | 0.57 % | (100 %) | — | — |
|
||||
| 50 % | grid | 86.77 % | 89.92 % | 6.470 µm | 6.025 µm |
|
||||
| | cluster + CNNs | 0.00 % | — | — | — |
|
||||
| | cluster + eta | 0.00 % | — | — | — |
|
||||
|
||||
At 0.5 % the grid chain and the cluster chain agree on efficiency and the grid
|
||||
chain is slightly sharper; from 1 % upwards the gap opens, because merged
|
||||
clusters fall outside all three energy windows and are dropped. The published
|
||||
reference points sit where they should: 0.8 µm for the cluster-based CNN and
|
||||
~1.1 µm for eta at 12 keV.
|
||||
|
||||
Above 10 % the cluster chains are not merely worse, they are gone, and it
|
||||
happens twice over. On 200 of these frames the finder itself returns 3446 raw
|
||||
clusters at 2 %, 5229 at 10 %, but only 1449 at 20 % and 213 at 50 %: the charge
|
||||
has merged into a few large connected objects rather than many small ones. Of
|
||||
what it does return, the fraction that falls inside one of the three
|
||||
single-/double-/triple-photon energy windows goes 76.5 % → 41.7 % → 22.2 % →
|
||||
0.9 %. The two effects multiply, leaving 10 / 0 / 0 usable clusters per 2000
|
||||
frames at 50 % against 21 348 / 3974 / 850 at 2 %. The purity and resolution of
|
||||
those rows are computed over a handful of matches and mean nothing, which is why
|
||||
they are bracketed or left out.
|
||||
|
||||
The two cluster chains do not depend on the grid checkpoint, so the five rows up
|
||||
to 10 % are byte-identical to the earlier comparison run at epoch 100 of
|
||||
`260831_12keV_Moench040_00`; the grid rows there moved by at most +0.7 points of
|
||||
efficiency and −0.9 points of purity at 10 %.
|
||||
|
||||
The grid chain keeps producing an image at 20 % and 50 %, but its own numbers
|
||||
have to be read carefully there:
|
||||
|
||||
* the model is extrapolating — it never saw anything above 10 % occupancy in
|
||||
training;
|
||||
* the matcher accepts a prediction within 1 px (25 µm) of a true photon, and at
|
||||
50 % occupancy that circle contains ~1.6 photons on average, so a prediction
|
||||
that is merely *near* a photon still counts. 86.77 % is therefore an upper
|
||||
bound on "found the right photon", not a resolution claim;
|
||||
* the honest signal is σ68: 0.593 µm at 0.5 %, then 0.945 / 1.979 / 6.025 µm at
|
||||
10 / 20 / 50 %. At 50 % the matched positions are spread over a quarter of
|
||||
the 25 µm matching window, so the chain detects that photons are there without
|
||||
locating them.
|
||||
|
||||
The generator reports how many photons share a cell with another, which is the
|
||||
ceiling a one-photon-per-cell output grid could reach: 95.20 % at 10 %, 90.62 %
|
||||
at 20 %, 78.69 % at 50 %. The measured efficiency sits above that ceiling at
|
||||
every point (96.37 / 93.56 / 86.77 %) because the offset channels are unbounded
|
||||
and a cell may report a position inside its neighbour — the same effect noted in
|
||||
the Results section. A finer output grid is what would turn that from an
|
||||
artefact of the matching radius into real resolution at these fluxes.
|
||||
|
||||
Gate G2 asked for σ ≤ 0.8 µm on 12 keV MC and ≥ 96 % efficiency at 1.7 %
|
||||
occupancy with purity at least as good as the cluster chain. The scan has no
|
||||
1.7 % point, so the claim is read off the harder 2 % one: 0.805 µm at 0.5 %,
|
||||
99.01 % efficiency and 99.79 % purity at 2 %, against 91.79 % and 98.00 % for
|
||||
the cluster chain there.
|
||||
|
||||
The comparison needs both torch and `aare`, so it runs in the `mlxid_demo`
|
||||
environment. On these 32×32 frames a `VarClusterFinder` is built per frame:
|
||||
reusing one, as `_processFrames` does, is exact at its 101×101 ROI (verified on
|
||||
real measurement frames) but overruns the internal hit buffer on frames this
|
||||
small.
|
||||
|
||||
## Measurement pipeline
|
||||
|
||||
`src/measurement.py` + `scripts/05_infer_measurement.py` take a run from raw ADU
|
||||
to a photon list in a single pass, with pedestal subtraction, common-mode removal
|
||||
and the 3D-LUT all running on the GPU.
|
||||
|
||||
```bash
|
||||
python scripts/05_infer_measurement.py --config Configs/infer_measurement_12keV.yaml \
|
||||
--run Edge_3filters_pos0_12keV
|
||||
python scripts/05_infer_measurement.py --config ... --run Flat_3filters_pos0_12keV
|
||||
python scripts/05_infer_measurement.py --config ... --run Pedestal_3filters_pos0_12keV # fake-rate test
|
||||
```
|
||||
|
||||
Each run writes, as `.npy` and `.png`: `binned_image` (reconstruction at
|
||||
`pixel_size / binning_factor`), `native_image` (the same photons rebinned to the
|
||||
25 µm pitch), `analog_image` (mean calibrated energy per frame — the classical
|
||||
native readout), plus `comparison.png` with the last two side by side, the energy
|
||||
spectrum, the per-frame photon count and `summary.json`.
|
||||
|
||||
`summary.json` reports the occupancy twice: averaged over the valid region, and
|
||||
**inside the illuminated area** (pixels above half the 99th-percentile density).
|
||||
For a knife-edge or slit run the second number is the one that describes the flux
|
||||
the model sees.
|
||||
|
||||
Measured on `Edge_3filters_pos0_12keV` (MOENCH040 @150 V, 12 keV, 140 files,
|
||||
14 M frames, 287 GB):
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| GPU calibration vs `UsefulFuncs.convertAduFrameToEnergyFrame` | agrees to 2.4e-6 keV (float32 rounding) |
|
||||
| pixel noise, raw | 0.1401 keV |
|
||||
| pixel noise, column common mode removed | **0.1291 keV** — the 0.13 keV the model was trained with |
|
||||
| frame-mean fluctuation | 28.5 eV → 1.0 eV after the correction |
|
||||
| pedestal stability over the whole run | −2 ADU = 0.015 keV, a tenth of the noise |
|
||||
| photon occupancy | **0.66 % inside the illuminated area** (0.16 % averaged over a ROI that is mostly knife-edge shadow). Matches the 0.69 % of the published DanMAX working point and sits inside the 0.2–10 % training range. |
|
||||
| fake rate on dark frames (cross-run pedestal, p>0.3) | **0 photons in 1000 frames** |
|
||||
| throughput | 5200–5900 frame/s while sharing the GPU with a training job → ~45 min for the full 14 M-frame run |
|
||||
|
||||
The MOENCH040 LUT is `(1740, 400, 400)`, so `convertAduFrameToEnergyFrame` takes
|
||||
its `else` branch (ADU from −1000 in steps of 10, signed natively). The MOENCH014
|
||||
LUT is the 1640-bin variant that starts at 0 ADU and handles negative values
|
||||
through `|adu|` and the sign; `GpuCalibrator` implements both (agreement with the
|
||||
numpy reference: 2e-6 keV).
|
||||
|
||||
Common mode `column_masked` takes the column median over the pixels without
|
||||
charge. The plain median is pulled up by the photons in the column, which on
|
||||
the full-chip XRF runs (0.7–1.3 % occupancy) leaves every pixel 4–7 meV low —
|
||||
tens of meV on a 3×3 sum, growing with the flux. At the 101×101 knife-edge ROI
|
||||
(~0.8 hit pixels per column) the effect is negligible and `column` is kept.
|
||||
|
||||
### Inference speed (RTX 4090)
|
||||
|
||||
| model | frame | precision | model only | end-to-end run |
|
||||
|---|---|---|---|---|
|
||||
| 12 keV `[32, 64, 64, 64]` | 101×101 | FP32 (TF32) | 11 665 frame/s (119 Mpx/s) | 7 805 frame/s (80 Mpx/s) |
|
||||
| | | FP16 + channels-last | 28 991 frame/s (296 Mpx/s) | 12 265 frame/s (125 Mpx/s) |
|
||||
| 5–30 keV `[32, 64, 128, 128]` | 400×400 | FP32 (TF32) | 428 frame/s (68 Mpx/s) | 360 frame/s (58 Mpx/s) |
|
||||
| | | FP16 + channels-last | 973 frame/s (156 Mpx/s) | 694 frame/s (111 Mpx/s) |
|
||||
| 3–30 keV `[32, 64, 96, 96]` (default) | 400×400 | FP16 + channels-last | 1 172 frame/s (188 Mpx/s) | **777 frame/s** (124 Mpx/s) |
|
||||
|
||||
At the same frame size the 12 keV model runs 1.7x more pixels per second than
|
||||
the 5-30 keV one. End-to-end keeps a smaller share of the model speed on
|
||||
101×101 frames (42-67 %) than on 400×400 frames (71-84 %). Per frame the loop
|
||||
adds ~0.05 ms of work that does not scale with the frame size: decode splits
|
||||
the batch frame by frame, and the energy histogram and image accumulation run
|
||||
once per frame. In FP16 that is more than the 0.04 ms the 12 keV model itself
|
||||
needs per 101×101 frame.
|
||||
|
||||
`inference.precision: fp16` runs the network under FP16 autocast in
|
||||
channels-last layout (`predict_fp16`). An FP16 head alone would round every
|
||||
energy to the FP16 grid: 7.3 meV steps below 15 keV, 14.6 meV above. That is
|
||||
harmless for the resolution, but a 50 eV spectrum then shows a comb. So the
|
||||
offsets and energy of the cells above threshold, about 1 % of the cells, are
|
||||
recomputed in FP32 from the same features. That costs nothing measurable;
|
||||
converting the whole feature map to FP32 for the head would cost 15 %. Both
|
||||
models are trained with AMP, and the FP16 photon list matches the FP32 one:
|
||||
- on MC, efficiency, purity, position RMS/σ68 and the energy core width agree
|
||||
to the last digit quoted;
|
||||
- on AgMo/CuCrCo, 99.997 % of the photons are identical, with positions within
|
||||
~20 nm. The only differences are the 0.03 % of photons at a cell border,
|
||||
where the two cells claiming the photon swap.
|
||||
|
||||
The poly config uses FP16; the 12 keV config still runs FP32, as its published
|
||||
numbers were made that way. In the FP16 poly loop the model takes 67 % of the
|
||||
time, decode 12 % and calibration 10 %. Reading the raw file runs in a prefetch
|
||||
thread. TF32 and batches above 32 bring nothing, because these convolutions are
|
||||
bandwidth-bound.
|
||||
|
||||
**Full-size MÖNCH, 800×1200** (virtual frames tiled 2×3 from real AgMo raw
|
||||
frames, ~6500 photons per frame; the Moench014 LUT tiled to 1640×800×1200 =
|
||||
6.3 GB on the GPU; frames served from RAM, so file reading is not included):
|
||||
|
||||
| model | model only, FP32 | model only, FP16 | end-to-end, FP16 |
|
||||
|---|---|---|---|
|
||||
| poly `[32, 64, 96, 96]` (default) | 90 frame/s | 198 frame/s | **144 frame/s** |
|
||||
| poly `[32, 64, 128, 128]` | 72 frame/s | 157 frame/s | — |
|
||||
| poly `[32, 64, 64, 64]` | 125 frame/s | 287 frame/s | — |
|
||||
| 12 keV `[32, 64, 64, 64]` | 124 frame/s | 302 frame/s | — |
|
||||
|
||||
Per 800×1200 frame, end to end in FP16 with the default model:
|
||||
- upload 0.25 ms;
|
||||
- calibration 0.54 ms;
|
||||
- model 4.95 ms;
|
||||
- decode 1.0 ms;
|
||||
- image + histogram 0.19 ms.
|
||||
|
||||
The pixel rate is the same as at 400×400 (≈ 190 Mpx/s for the model), and batch
|
||||
size (4–16) makes no difference. The FP32 path needs ~15–22 GB at batch 16
|
||||
next to the LUT; FP16 needs 12 GB. Reading the raw file needs 1.9 MB per
|
||||
frame, 280 MB/s at 144 frame/s.
|
||||
|
||||
The last two 128-channel layers carry 92 % of the MACs of `[32, 64, 128, 128]`.
|
||||
Narrower variants were trained and compared (see "Choosing the size"), and
|
||||
`[32, 64, 96, 96]` replaced it as the default at no measurable cost.
|
||||
|
||||
## Knife-edge test — `Notebooks/KnifeEdge_*.ipynb`
|
||||
|
||||
Four flux points of the same DanMAX knife-edge scan, one notebook each, all with
|
||||
the same ROI and the same ESF and fit as `Plotting/fig_knife_edge.py --fit odr`
|
||||
(`generate_presampled_esf` + `get_odr_fitting` of
|
||||
`DeepLearning/src/funcs_postprocess.py`, ESF bins 0.3 µm, symmetric ±4σ window),
|
||||
so the only thing that differs between the rows is the reconstruction. The edge
|
||||
sits in the same place at every flux point, so one ROI serves all four and the
|
||||
notebooks are directly comparable:
|
||||
|
||||
| notebook | measurement | frames | occupancy (illuminated) | classical chains available |
|
||||
|---|---|---|---|---|
|
||||
| `KnifeEdge_0filters` | `{Edge,Flat}_0filters_12keV` | 3.5 M | 9.42 % | none — this point was never clustered |
|
||||
| `KnifeEdge_1filters` | `{Edge,Flat}_1filters_12keV` | 7 M | 3.90 % | eta only (the CNN images are older model versions) |
|
||||
| `KnifeEdge_2filters` | `{Edge,Flat}_2filters_12keV` | 7 M | 1.59 % | eta + the 1/2/3-photon CNNs |
|
||||
| `KnifeEdge_3filters_pos0` | `{Edge,Flat}_3filters_pos0_12keV` | 14 M | 0.66 % | eta + the 1/2/3-photon CNNs |
|
||||
|
||||
LSF width σ [µm], with MTF50 [lp/mm] of the fitted Gaussian in brackets:
|
||||
|
||||
| reconstruction | 0 filters | 1 filter | 2 filters | 3 filters |
|
||||
|---|---|---|---|---|
|
||||
| eta interpolation | — | 1.506 ± 0.023 (124) | 1.483 ± 0.024 (126) | 1.536 ± 0.019 (122) |
|
||||
| cluster + CNN, 1 photon | — | — | 1.352 ± 0.022 (139) | 1.355 ± 0.016 (138) |
|
||||
| cluster + CNN, ≤2 photons | — | — | 1.372 ± 0.022 (137) | 1.380 ± 0.016 (136) |
|
||||
| cluster + CNN, ≤3 photons | — | — | 1.386 ± 0.018 (135) | 1.381 ± 0.017 (136) |
|
||||
| **GridBased 12 keV** | **1.473 ± 0.017 (127)** | **1.388 ± 0.020 (135)** | **1.346 ± 0.019 (139)** | **1.360 ± 0.019 (138)** |
|
||||
| GridBased poly 2–20 keV | 1.856 ± 0.037 (101) | 1.551 ± 0.028 (121) | 1.391 ± 0.018 (135) | 1.420 ± 0.021 (132) |
|
||||
|
||||
The ODR model is `A/2 (1 + erf((x - c)/(sqrt(2) sigma))) + B`, so σ is the width
|
||||
of the Gaussian LSF and `MTF50 = 1000 sqrt(ln 2 / 2) / (pi sigma)`. The GridBased
|
||||
rows are the self-flattened reconstructions. (Until 2026-09-28 this table took
|
||||
the fitted σ for √2 σ, so its MTF50 was √2 too high, and binned the ESF with an
|
||||
older copy of `generate_presampled_esf` that made σ ~3 % too small.) Photon
|
||||
counts are compared within a flux point only; every chain there sees the same
|
||||
beam, so their ratio is the ratio of quantum efficiencies and the relative
|
||||
DQE ∝ QE·MTF² is well defined without the absolute flux. MTF(200 lp/mm) is
|
||||
measured from the LSF (`Plotting/knife_edge_numbers.py`):
|
||||
|
||||
| flux point | GridBased vs ≤3-photon chain | GridBased vs eta | sub-pixel excess rms |
|
||||
|---|---|---|---|
|
||||
| 0 filters, 9.42 % | — | — | 18.3 % → 1.6 % |
|
||||
| 1 filter, 3.90 % | — | 2.46x photons, 3.24x DQE | 19.8 % → 3.0 % |
|
||||
| 2 filters, 1.59 % | 1.044x photons, 1.17x DQE | 1.47x photons, 2.82x DQE | 21.6 % → 3.8 % |
|
||||
| 3 filters, 0.66 % | 1.014x photons, 1.23x DQE | 1.19x photons, 2.60x DQE | 22.6 % → 4.3 % |
|
||||
|
||||
At the two low-flux points, where the cluster chain is in its comfort zone, the
|
||||
grid chain matches the sharpest cluster chain to within the errors and collects
|
||||
as many photons as the ≤3-photon chain or slightly more, which puts its DQE at
|
||||
200 lp/mm 17–23 % above that chain and 2.6–2.8x above eta. The interesting part
|
||||
is what happens above it: there is no comparable cluster + CNN image beyond
|
||||
1.59 % — at 3.90 % only older model versions were ever run, at 9.42 % the
|
||||
measurement was never clustered at all — while the grid chain keeps resolving
|
||||
the edge: σ stays at 1.35–1.36 µm up to 1.59 % and grows to 1.39 and 1.47 µm at
|
||||
3.90 and 9.42 %.
|
||||
|
||||
The polychromatic 2–20 keV MOENCH040 model (`KnifeEdge_poly2to20keV_Moench040.ipynb`,
|
||||
same runs and processing) is 3–4 % wider at the two low-flux points, on par with
|
||||
the ≤3-photon chain, and falls behind above 4 %, where its fit also degrades
|
||||
(χ²/NDF 3.4 and 7.4). Its 12 keV line moves from 12.05 to 11.64 keV with flux;
|
||||
the plain column common mode is the suspect (on the Siemens star the masked one
|
||||
moved the 15 keV line from 14.45 to 15.01 keV), not yet tested on the knife edge.
|
||||
|
||||
Sub-pixel flattening is about image uniformity rather than resolution: it takes
|
||||
the sub-pixel phase from ~20 % to ~2–4 % excess rms.
|
||||
|
||||
The ESF width depends strongly on the ROI: a band of 500 rows across this
|
||||
strongly slanted edge gives a width 1.6x that of the published 230-row ROI.
|
||||
Cross-method comparisons are only meaningful at a fixed ROI.
|
||||
|
||||
## Results — polychromatic, default `Results/260919_poly3to30keV_Moench014_c96_00`
|
||||
|
||||
1.2 M training frames, flat **3–30 keV**, occupancy log-uniform 0.2–10 %. Every
|
||||
photon gets its own energy, conversion depth and charge cloud from the
|
||||
α(E,t)/β(E,t) table `data/charge_lut_Moench014_150V_3to30keV.npz` (WP1.1,
|
||||
validated by `01b_validate_charge_lut.py`). GridNet channels
|
||||
**[32, 64, 96, 96]** (R = 4, 157 636 parameters), 300 epochs, `best.pth` =
|
||||
epoch 224. It has been the default in `infer_measurement_poly_Moench014.yaml`
|
||||
since 2026-09-19. Fixed-occupancy scan at threshold 0.3:
|
||||
|
||||
| occupancy | efficiency | purity | RMS | σ68 | energy σ68 | sub-pixel non-unif. |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 0.5 % | 99.67 % | 99.73 % | 1.70 µm | 0.99 µm | 0.28 keV | 22.2 % |
|
||||
| 1 % | 99.42 % | 99.54 % | 1.78 µm | 1.04 µm | 0.29 keV | 22.2 % |
|
||||
| 2 % | 98.88 % | 99.19 % | 1.89 µm | 1.08 µm | 0.31 keV | 21.8 % |
|
||||
| 5 % | 97.25 % | 98.07 % | 2.29 µm | 1.28 µm | 0.42 keV | 18.3 % |
|
||||
| 10 % | 94.37 % | 96.22 % | 2.96 µm | 1.70 µm | 0.89 keV | 16.3 % |
|
||||
|
||||
Efficiencies include the 3–5 keV photons (97–98 % found), which the 5–30 keV
|
||||
model never saw. Against energy (`scripts/07_energy_response.py`, occupancy
|
||||
≤ 2.5 %, 4.3e5 matched photons, 0.25 keV bins):
|
||||
|
||||
| E_true | core σ | line position g(E) − E | tails, \|ΔE\| > 1 keV | efficiency |
|
||||
|---|---|---|---|---|
|
||||
| 3.1 keV | 0.13 keV * | +125 meV * | 2.8 % | 97.5 % |
|
||||
| 3.6 keV | 0.23 keV | +16 meV | 2.3 % | 97.6 % |
|
||||
| 4.1 keV | 0.26 keV | +4 meV | 2.3 % | 98.0 % |
|
||||
| 5.4 keV | 0.26 keV | −12 meV | 3.0 % | 98.3 % |
|
||||
| 7.9 keV | 0.26 keV | 0 meV | 4.0 % | 98.8 % |
|
||||
| 12.1 keV | 0.28 keV | −7 meV | 4.3 % | 99.2 % |
|
||||
| 17.4 keV | 0.27 keV | −11 meV | 4.4 % | 99.5 % |
|
||||
| 22.1 keV | 0.30 keV | 0 meV | 4.7 % | 99.5 % |
|
||||
| 27.6 keV | 0.31 keV | −5 meV | 4.9 % | 99.7 % |
|
||||
| 29.6 keV | 0.24 keV * | −83 meV * | 7.0 % | 99.6 % |
|
||||
|
||||
\* within ~0.75 keV of a training edge, where the line is shifted and the
|
||||
energy scale compressed. Between 4 and 28 keV the line position stays within
|
||||
25 meV.
|
||||
|
||||
The `energy_bias_keV` of `eval_summary.json` is the *mean* per 2.5 keV bin. It
|
||||
is set by the 3–7 % of photons in the tails, which the bounded range cuts from
|
||||
one side, so it is pulled towards the centre (~+0.1 keV at 5–12 keV) even where
|
||||
the line does not move. Correcting per photon with the mean is therefore wrong;
|
||||
the notebooks invert the core position g(E) instead. With the 3–30 keV model
|
||||
that correction only matters below ~4 keV.
|
||||
|
||||
### Choosing the size — `Results/overnight_poly3to30keV/report`
|
||||
|
||||
Four networks trained overnight on the same 3–30 keV frames
|
||||
(`scripts/overnight_poly3to30keV.sh`, report by `scripts/08_compare_models.py`):
|
||||
|
||||
| channels | params | FP16 frame/s (400×400) | MC 1 %: RMS / E σ68 / purity | MC 10 %: E σ68 / purity | XRF FWHM Co / Cu / Mo / Ag [keV] | dark-run photons / 1000 frames |
|
||||
|---|---|---|---|---|---|---|
|
||||
| [32, 64, 128, 128] | 240 772 | 965 | 1.772 µm / 0.290 keV / 99.55 % | 0.872 keV / 96.28 % | 0.62 / 0.72 / 0.81 / 0.94 | 0 |
|
||||
| **[32, 64, 96, 96]** | 157 636 | **1 185** | 1.777 µm / 0.291 keV / 99.54 % | 0.889 keV / 96.22 % | 0.62 / 0.72 / 0.82 / 0.95 | **0** |
|
||||
| [32, 64, 64, 64] | 92 932 | 1 761 | 1.785 µm / 0.292 keV / 99.52 % | 0.919 keV / 96.17 % | 0.63 / 0.72 / 0.82 / 0.95 | 15 (all 2.3–3.2 keV) |
|
||||
| [32, 64, 128] (R = 3) | 93 188 | 1 712 | 1.790 µm / 0.297 keV / 99.37 % | 1.040 keV / 95.64 % | 0.63 / 0.73 / 0.82 / 0.93 | 8 (2.4–3.7 keV) |
|
||||
|
||||
`[32, 64, 96, 96]` matches the widest network on every number and is 23 %
|
||||
faster. (The XRF runs of this comparison were redone with clean FP16 energies,
|
||||
see Inference speed.) `[32, 64, 64, 64]` loses ~5 % of energy resolution at 10 % occupancy
|
||||
and reports photons on dark frames below 3.2 keV. Three layers (R = 3) cost
|
||||
the most at high occupancy.
|
||||
|
||||
### Previous default — 5–30 keV `[32, 64, 128, 128]`, `Results/260901_poly5to30keV_Moench014_00`
|
||||
|
||||
Same architecture and data volume, flat 5–30 keV, `best.pth` = epoch 290. MC at
|
||||
1 % occupancy: 99.52 % efficiency, 99.59 % purity, 1.76 µm RMS, 0.29 keV energy
|
||||
σ68. Its 5 keV edge shifted Cr Kα (5.41 keV) by +52 meV on MC and compressed
|
||||
the scale there (g′ = 0.82). On data that meant +33 meV with a 0.18 keV core,
|
||||
which is why the range was extended. Its XRF reconstructions carry the tag
|
||||
`_poly5to30`.
|
||||
|
||||
## XRF test — `Notebooks/XRF_*.ipynb`
|
||||
|
||||
Two flood-field runs from the 2603 MaxIV XRF series (MOENCH014 @150 V, full
|
||||
400×400 chip, slit factor 10), reconstructed with the default 3–30 keV
|
||||
`[32, 64, 96, 96]` model and `Configs/infer_measurement_poly_Moench014.yaml`:
|
||||
|
||||
* `AgMo_1_factor_10`: 0.69 % occupancy, 1.05e8 photons;
|
||||
* `CuCrCo_1_factor_10`: 1.29 % occupancy, 1.99e8 photons, 12 keV beam.
|
||||
|
||||
The reference is the classical 3×3 sum around a local maximum on the *same*
|
||||
calibrated frames (first 10 k frames), with no model. The yaml carries more
|
||||
samples and the full flux series (slit factor 1–20). The reconstructions of the
|
||||
previous 5–30 keV model are kept as `<run>_poly5to30`, and those of all four
|
||||
sizes as `<run>_c128/_c96/_c64/_r3`.
|
||||
|
||||
**Energy resolution.** Core σ of the fitted line in keV, FWHM of the whole
|
||||
line shape in brackets, straight from the model (no correction):
|
||||
|
||||
| line | E [keV] | GridBased | classical 3×3 | FWHM grid / 3×3 | MC core σ |
|
||||
|---|---|---|---|---|---|
|
||||
| Cr Kα | 5.41 | 0.245 (0.58) | 0.398 (0.94) | 0.62 | 0.256 |
|
||||
| Co Kα | 6.93 | 0.265 (0.62) | 0.408 (0.96) | 0.65 | 0.264 |
|
||||
| Cu Kα | 8.04 | 0.305 (0.72) | 0.441 (1.04) | 0.69 | 0.267 |
|
||||
| elastic | 12.0 | 0.311 (0.73) ‡ | 0.470 (1.11) ‡ | 0.66 | 0.279 |
|
||||
| Mo Kα | 17.44 | 0.327 (0.82) | 0.464 (1.09) | 0.75 | 0.275 |
|
||||
| Mo Kβ | 19.64 | 0.353 (0.83) | 0.492 (1.16) | 0.72 | 0.290 |
|
||||
| Ag Kα | 22.10 | 0.378 (0.95) | 0.489 (1.15) | 0.82 | 0.301 |
|
||||
|
||||
‡ FWHM = 2.355 σ.
|
||||
|
||||
* The grid lines are 18–38 % narrower than the 3×3 sum at every energy. The
|
||||
core σ stays below the 0.38 keV noise floor of a fixed 3×3 sum
|
||||
(√9 × 0.126 keV) at every line, the gain that design decision D5 anticipated.
|
||||
In CuCrCo that separates Cu Kα from Co Kβ; the 3×3 sum shows Cu only as a
|
||||
shoulder.
|
||||
* Cr and Co match the MC within ±5 %. Cu, the elastic line and the lines at
|
||||
17–22 keV are 12–26 % wider, an extra term that grows with E (~1 % of E) and
|
||||
that the MC noise model (0.13 keV per pixel) does not contain.
|
||||
Pixel-to-pixel gain residuals of the LUT would do this (WP1.3).
|
||||
* The previous 5–30 keV model put Cr Kα 0.4 keV above its training edge and
|
||||
compressed it (0.182 keV core, 0.48 keV FWHM, +33 meV); the MC correction
|
||||
restored the width but overshot the position. With the 3 keV edge the line
|
||||
needs no correction.
|
||||
|
||||
**Line positions.** The grid puts every line within 0.04 keV of the tables (Cr Kα
|
||||
+0.01 keV). The classical 3×3 sum reads 0.05–0.10 keV high: the MOENCH014 LUT
|
||||
(2025-03-05) is 0.3–1 % high (~0.9 % at 5–8 keV, 0.3–0.5 % at 17–22 keV). The
|
||||
MC correction changes no line by more than 12 meV.
|
||||
|
||||
**Efficiency**, without truth, against the classical finder:
|
||||
|
||||
| | AgMo | CuCrCo | MC |
|
||||
|---|---|---|---|
|
||||
| isolated photons ≥ 5 keV found | 99.97 % | 99.99 % | 99.96 % (no neighbour within 4 px, 1 %) |
|
||||
| isolated photons 3–5 keV found | 92.9 % | 100.0 % | 97–98 % |
|
||||
| grid / classical photon count | 1.091 | 1.067 | — |
|
||||
| classical clusters holding ≥ 2 grid photons | 8.5 % | 10.2 % | Poisson: 8.3 % / 15.0 % |
|
||||
| reconstructed / deposited energy | 0.997 | 0.996 | — |
|
||||
|
||||
The extra grid photons are pile-up that the 3×3 finder merges; in CuCrCo the
|
||||
pile-up continuum at 13–25 keV is 5–10× lower than in the classical spectrum.
|
||||
On a dark run (`Pedestal_CuCrCo_1`, 1000 full frames) the model reports
|
||||
**0 photons** (< 2e-8 per pixel per frame).
|
||||
|
||||
The sub-pixel phase of these flood fields has 48 % (AgMo) and 20 % (CuCrCo)
|
||||
excess rms against 22 % on MC, so R1 is worse on data at high energies.
|
||||
Self-flattening takes both to 0.5 % and 3.2 %.
|
||||
|
||||
## Status
|
||||
|
||||
- [x] WP0 data contract, self-tests
|
||||
- [x] WP1.1 α(E,t) / β(E,t) charge-cloud LUT, MOENCH014 @150 V, with leave-one-out validation
|
||||
- [x] WP1.2 frame generator: stamp reuse at 12 keV, per-photon LUT sampling at 3–30 keV
|
||||
- [ ] WP1.3 noise / physics completion (escape peak, Compton, LUT gain residuals) and gate G1 (simulated vs measured spectra); the XRF widths at 17–22 keV ask for the gain term
|
||||
- [x] WP2 halo / valid-region handling, verified exact; edge augmentation
|
||||
- [ ] WP2 ablation of R and training-frame size
|
||||
- [x] WP3 model, loss, decode, training loop; 12 keV, 5–30 keV and 3–30 keV models
|
||||
- [x] WP3 network size scan on 3–30 keV (four widths / depths); `[32, 64, 96, 96]` is the default
|
||||
- [x] WP4 metrics: efficiency/purity, RMS/σ68, energy, pair resolution, sub-pixel uniformity
|
||||
- [x] WP4 baseline comparison against eta interpolation and the 1/2/3-photon models (gate G2 passed)
|
||||
- [x] WP4 gate G3: efficiency, purity and energy response tabulated over 3–30 keV; self-flattening available
|
||||
- [x] WP5.1/5.2 measurement pipeline: GPU calibration (both LUT variants, masked common mode), inference, images
|
||||
- [x] WP5.3 XRF lines (AgMo, CuCrCo): positions, energy resolution, efficiency against the classical sum
|
||||
- [ ] WP5.3 energy-resolved imaging (the XRF runs are flood fields; needs a structured sample)
|
||||
- [x] WP5.4 ESF / MTF / relative DQE from the knife edge at four flux points (0.66–9.42 % occupancy), against every published chain
|
||||
- [ ] WP5.4 SOLEIL 15 keV Siemens star
|
||||
- [x] WP5.5 fake rate on dark runs (12 keV: 0 / 1000 frames of 101×101; poly: 0 / 1000 full frames)
|
||||
- [x] gate G4: knife-edge σ = 1.360 µm (MTF50 138 lp/mm) at 0.66 %, equal within the errors to the best published chain (CNN 1 photon, 1.355 µm, 138 lp/mm); XRF lines resolved and in place
|
||||
- [ ] WP6 extensions (full-size MÖNCH, ONNX/TensorRT, online), WP7 write-up
|
||||
|
After Width: | Height: | Size: 134 KiB |
|
After Width: | Height: | Size: 246 KiB |
|
After Width: | Height: | Size: 70 KiB |
@@ -0,0 +1,56 @@
|
||||
experiment:
|
||||
name: 12keV_Moench040
|
||||
results_dir: Results
|
||||
data:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/GridBased/12keV_Moench040_150V
|
||||
train_shards:
|
||||
- 0
|
||||
- 11
|
||||
val_shards:
|
||||
- 0
|
||||
- 1
|
||||
max_train_frames: null
|
||||
max_val_frames: 8000
|
||||
input_scale: 12.0
|
||||
energy_scale: 12.0
|
||||
augment: true
|
||||
batch_size_train: 256
|
||||
batch_size_val: 512
|
||||
num_workers: 8
|
||||
model:
|
||||
channels:
|
||||
- 32
|
||||
- 64
|
||||
- 64
|
||||
- 64
|
||||
predict_energy: true
|
||||
norm: none
|
||||
prior_prob: 0.01
|
||||
loss:
|
||||
w_obj: 1.0
|
||||
w_off: 1.0
|
||||
w_ene: 0.1
|
||||
focal_alpha: 0.25
|
||||
focal_gamma: 2.0
|
||||
smooth_l1_beta_offset: 0.01
|
||||
smooth_l1_beta_energy: 0.02
|
||||
training:
|
||||
epochs: 120
|
||||
lr: 0.001
|
||||
weight_decay: 0.0
|
||||
scheduler_factor: 0.5
|
||||
scheduler_patience: 4
|
||||
amp: true
|
||||
seed: 0
|
||||
checkpoint_epochs:
|
||||
- 20
|
||||
- 40
|
||||
- 60
|
||||
- 80
|
||||
- 100
|
||||
- 120
|
||||
eval:
|
||||
threshold: 0.5
|
||||
nms_kernel: 3
|
||||
match_radius: 1.0
|
||||
pixel_size_um: 25.0
|
||||
@@ -0,0 +1,707 @@
|
||||
{
|
||||
"0.5%": {
|
||||
"occupancy": 0.005,
|
||||
"summary": {
|
||||
"n_true": 23133,
|
||||
"n_pred": 21671,
|
||||
"n_match": 21662,
|
||||
"efficiency": 0.9364111874810876,
|
||||
"purity": 0.9995846984449264,
|
||||
"f1": 0.9669672350682975,
|
||||
"rms_x_um": 0.8069253991016199,
|
||||
"rms_y_um": 0.8141111360845683,
|
||||
"rms_1d_um": 0.8106481995439455,
|
||||
"sigma68_1d_um": 0.5971485185623169,
|
||||
"bias_x_um": 0.029450980219833518,
|
||||
"bias_y_um": 0.05757446632899468,
|
||||
"energy_bias_keV": 0.00028054833731353256,
|
||||
"energy_rms_keV": 0.07483918327806448,
|
||||
"energy_sigma68_keV": 0.07464508714675899,
|
||||
"subpixel_nonuniformity": 0.1002893136346688
|
||||
},
|
||||
"roc": [
|
||||
[
|
||||
0.05,
|
||||
0.9763171443281277,
|
||||
0.9989464442493415,
|
||||
0.8159768304327072
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.9763171443281277,
|
||||
0.9989464442493415,
|
||||
0.8159768304327072
|
||||
],
|
||||
[
|
||||
0.2,
|
||||
0.9763171443281277,
|
||||
0.9989464442493415,
|
||||
0.8159768304327072
|
||||
],
|
||||
[
|
||||
0.3,
|
||||
0.9763171443281277,
|
||||
0.9989464442493415,
|
||||
0.8159768304327072
|
||||
],
|
||||
[
|
||||
0.4,
|
||||
0.9733996910931869,
|
||||
0.9989432898908066,
|
||||
0.8167144888609401
|
||||
],
|
||||
[
|
||||
0.5,
|
||||
0.9359876437274756,
|
||||
0.999633431085044,
|
||||
0.8222016542994832
|
||||
],
|
||||
[
|
||||
0.6,
|
||||
0.8948000686459585,
|
||||
0.9998082454458294,
|
||||
0.8305491713874892
|
||||
],
|
||||
[
|
||||
0.7,
|
||||
0.8603054745151879,
|
||||
1.0,
|
||||
0.8374268117182482
|
||||
],
|
||||
[
|
||||
0.8,
|
||||
0.8237515016303415,
|
||||
1.0,
|
||||
0.8467556683498757
|
||||
],
|
||||
[
|
||||
0.9,
|
||||
0.7707224987128882,
|
||||
1.0,
|
||||
0.8538555501900706
|
||||
],
|
||||
[
|
||||
0.95,
|
||||
0.719238029860992,
|
||||
1.0,
|
||||
0.8661173888491417
|
||||
],
|
||||
[
|
||||
0.98,
|
||||
0.632744122189806,
|
||||
1.0,
|
||||
0.8919477349473682
|
||||
]
|
||||
],
|
||||
"pair": {
|
||||
"edges": [
|
||||
0.0,
|
||||
0.5,
|
||||
1.0,
|
||||
1.5,
|
||||
2.0,
|
||||
2.5,
|
||||
3.0,
|
||||
4.0,
|
||||
6.0
|
||||
],
|
||||
"n_true": [
|
||||
30.0,
|
||||
72.0,
|
||||
110.0,
|
||||
133.0,
|
||||
166.0,
|
||||
214.0,
|
||||
425.0,
|
||||
974.0,
|
||||
3392.0
|
||||
],
|
||||
"n_match": [
|
||||
15.0,
|
||||
36.0,
|
||||
68.0,
|
||||
105.0,
|
||||
151.0,
|
||||
207.0,
|
||||
405.0,
|
||||
927.0,
|
||||
3243.0
|
||||
],
|
||||
"efficiency": [
|
||||
0.5,
|
||||
0.5,
|
||||
0.6181818181818182,
|
||||
0.7894736842105263,
|
||||
0.9096385542168675,
|
||||
0.9672897196261683,
|
||||
0.9529411764705882,
|
||||
0.9517453798767967,
|
||||
0.9560731132075472
|
||||
]
|
||||
}
|
||||
},
|
||||
"1%": {
|
||||
"occupancy": 0.01,
|
||||
"summary": {
|
||||
"n_true": 46085,
|
||||
"n_pred": 42138,
|
||||
"n_match": 42125,
|
||||
"efficiency": 0.9140718238038408,
|
||||
"purity": 0.9996914898666287,
|
||||
"f1": 0.9549663919839497,
|
||||
"rms_x_um": 0.8771180639142474,
|
||||
"rms_y_um": 0.8505284150844781,
|
||||
"rms_1d_um": 0.8640159984688428,
|
||||
"sigma68_1d_um": 0.6083438944816589,
|
||||
"bias_x_um": 0.03757140162436828,
|
||||
"bias_y_um": 0.06257573362627794,
|
||||
"energy_bias_keV": 0.0010086130883644171,
|
||||
"energy_rms_keV": 0.07440421101232769,
|
||||
"energy_sigma68_keV": 0.07450108985900879,
|
||||
"subpixel_nonuniformity": 0.10732684673233057
|
||||
},
|
||||
"roc": [
|
||||
[
|
||||
0.05,
|
||||
0.9549361812972128,
|
||||
0.9991823385118561,
|
||||
0.8634292507991568
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.9549361812972128,
|
||||
0.9991823385118561,
|
||||
0.8634292507991568
|
||||
],
|
||||
[
|
||||
0.2,
|
||||
0.9549361812972128,
|
||||
0.9991823385118561,
|
||||
0.8634292507991568
|
||||
],
|
||||
[
|
||||
0.3,
|
||||
0.9549361812972128,
|
||||
0.9991823385118561,
|
||||
0.8634292507991568
|
||||
],
|
||||
[
|
||||
0.4,
|
||||
0.9512025701137449,
|
||||
0.9992702727355651,
|
||||
0.8634067361783272
|
||||
],
|
||||
[
|
||||
0.5,
|
||||
0.912824520274377,
|
||||
0.9997147204260175,
|
||||
0.8694773749521033
|
||||
],
|
||||
[
|
||||
0.6,
|
||||
0.8734045324303203,
|
||||
0.9999005964214712,
|
||||
0.8792576600557114
|
||||
],
|
||||
[
|
||||
0.7,
|
||||
0.8391942346097074,
|
||||
1.0,
|
||||
0.8867004362713521
|
||||
],
|
||||
[
|
||||
0.8,
|
||||
0.8051575931232091,
|
||||
1.0,
|
||||
0.8950094142285888
|
||||
],
|
||||
[
|
||||
0.9,
|
||||
0.7541026308934619,
|
||||
1.0,
|
||||
0.9060466598739252
|
||||
],
|
||||
[
|
||||
0.95,
|
||||
0.6986194321437874,
|
||||
1.0,
|
||||
0.9245163116881274
|
||||
],
|
||||
[
|
||||
0.98,
|
||||
0.6051054962229747,
|
||||
1.0,
|
||||
0.9456982525459215
|
||||
]
|
||||
],
|
||||
"pair": {
|
||||
"edges": [
|
||||
0.0,
|
||||
0.5,
|
||||
1.0,
|
||||
1.5,
|
||||
2.0,
|
||||
2.5,
|
||||
3.0,
|
||||
4.0,
|
||||
6.0
|
||||
],
|
||||
"n_true": [
|
||||
70.0,
|
||||
257.0,
|
||||
429.0,
|
||||
549.0,
|
||||
633.0,
|
||||
710.0,
|
||||
1367.0,
|
||||
2724.0,
|
||||
4740.0
|
||||
],
|
||||
"n_match": [
|
||||
34.0,
|
||||
123.0,
|
||||
238.0,
|
||||
412.0,
|
||||
592.0,
|
||||
676.0,
|
||||
1313.0,
|
||||
2591.0,
|
||||
4496.0
|
||||
],
|
||||
"efficiency": [
|
||||
0.4857142857142857,
|
||||
0.4785992217898833,
|
||||
0.5547785547785548,
|
||||
0.7504553734061931,
|
||||
0.9352290679304898,
|
||||
0.952112676056338,
|
||||
0.9604974396488661,
|
||||
0.9511747430249633,
|
||||
0.9485232067510548
|
||||
]
|
||||
}
|
||||
},
|
||||
"2%": {
|
||||
"occupancy": 0.02,
|
||||
"summary": {
|
||||
"n_true": 91745,
|
||||
"n_pred": 80535,
|
||||
"n_match": 80505,
|
||||
"efficiency": 0.8774865115265137,
|
||||
"purity": 0.9996274911529148,
|
||||
"f1": 0.934583236591595,
|
||||
"rms_x_um": 0.9062968560920226,
|
||||
"rms_y_um": 0.9036639447537416,
|
||||
"rms_1d_um": 0.9050500337729438,
|
||||
"sigma68_1d_um": 0.6241321563720703,
|
||||
"bias_x_um": 0.037169365266577575,
|
||||
"bias_y_um": 0.05946783403174254,
|
||||
"energy_bias_keV": 0.0007606992869042187,
|
||||
"energy_rms_keV": 0.07450746470698477,
|
||||
"energy_sigma68_keV": 0.07439136505126953,
|
||||
"subpixel_nonuniformity": 0.136064844482477
|
||||
},
|
||||
"roc": [
|
||||
[
|
||||
0.05,
|
||||
0.9168807419340793,
|
||||
0.9989563567362428,
|
||||
0.8890069983133503
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.9168807419340793,
|
||||
0.9989563567362428,
|
||||
0.8890069983133503
|
||||
],
|
||||
[
|
||||
0.2,
|
||||
0.9168807419340793,
|
||||
0.9989563567362428,
|
||||
0.8890069983133503
|
||||
],
|
||||
[
|
||||
0.3,
|
||||
0.9168807419340793,
|
||||
0.9989563567362428,
|
||||
0.8890069983133503
|
||||
],
|
||||
[
|
||||
0.4,
|
||||
0.9139635128662864,
|
||||
0.9990956687291765,
|
||||
0.8897402274953791
|
||||
],
|
||||
[
|
||||
0.5,
|
||||
0.8770409718291462,
|
||||
0.9996526054590571,
|
||||
0.8984772887356761
|
||||
],
|
||||
[
|
||||
0.6,
|
||||
0.8434710671833501,
|
||||
0.9999483817684406,
|
||||
0.9070232836914548
|
||||
],
|
||||
[
|
||||
0.7,
|
||||
0.8102930291287499,
|
||||
1.0,
|
||||
0.9146903664251781
|
||||
],
|
||||
[
|
||||
0.8,
|
||||
0.7783341315800931,
|
||||
1.0,
|
||||
0.9218143778572377
|
||||
],
|
||||
[
|
||||
0.9,
|
||||
0.7249096529803631,
|
||||
1.0,
|
||||
0.9316294201788095
|
||||
],
|
||||
[
|
||||
0.95,
|
||||
0.6720947446336047,
|
||||
1.0,
|
||||
0.9400250797214569
|
||||
],
|
||||
[
|
||||
0.98,
|
||||
0.5827056211085471,
|
||||
1.0,
|
||||
0.9581336780761671
|
||||
]
|
||||
],
|
||||
"pair": {
|
||||
"edges": [
|
||||
0.0,
|
||||
0.5,
|
||||
1.0,
|
||||
1.5,
|
||||
2.0,
|
||||
2.5,
|
||||
3.0,
|
||||
4.0,
|
||||
6.0
|
||||
],
|
||||
"n_true": [
|
||||
371.0,
|
||||
952.0,
|
||||
1465.0,
|
||||
1900.0,
|
||||
2135.0,
|
||||
2119.0,
|
||||
4094.0,
|
||||
5721.0,
|
||||
4210.0
|
||||
],
|
||||
"n_match": [
|
||||
176.0,
|
||||
446.0,
|
||||
809.0,
|
||||
1439.0,
|
||||
1969.0,
|
||||
2013.0,
|
||||
3863.0,
|
||||
5437.0,
|
||||
3991.0
|
||||
],
|
||||
"efficiency": [
|
||||
0.4743935309973046,
|
||||
0.4684873949579832,
|
||||
0.5522184300341297,
|
||||
0.7573684210526316,
|
||||
0.922248243559719,
|
||||
0.9499764039641341,
|
||||
0.9435759648265755,
|
||||
0.950358328963468,
|
||||
0.9479809976247031
|
||||
]
|
||||
}
|
||||
},
|
||||
"5%": {
|
||||
"occupancy": 0.05,
|
||||
"summary": {
|
||||
"n_true": 229596,
|
||||
"n_pred": 178693,
|
||||
"n_match": 178615,
|
||||
"efficiency": 0.7779534486663531,
|
||||
"purity": 0.9995634971711259,
|
||||
"f1": 0.8749439735089607,
|
||||
"rms_x_um": 1.099822974575873,
|
||||
"rms_y_um": 1.0991446082401635,
|
||||
"rms_1d_um": 1.0994958355148743,
|
||||
"sigma68_1d_um": 0.6926536560058594,
|
||||
"bias_x_um": 0.043093383777743244,
|
||||
"bias_y_um": 0.053363671092027595,
|
||||
"energy_bias_keV": 0.00043349460802242964,
|
||||
"energy_rms_keV": 0.07511608523801999,
|
||||
"energy_sigma68_keV": 0.07507779865264892,
|
||||
"subpixel_nonuniformity": 0.19363629313163472
|
||||
},
|
||||
"roc": [
|
||||
[
|
||||
0.05,
|
||||
0.8082587151177953,
|
||||
0.9990973371445765,
|
||||
1.083904970790536
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.8082587151177953,
|
||||
0.9990973371445765,
|
||||
1.083904970790536
|
||||
],
|
||||
[
|
||||
0.2,
|
||||
0.8082587151177953,
|
||||
0.9990973371445765,
|
||||
1.083904970790536
|
||||
],
|
||||
[
|
||||
0.3,
|
||||
0.8082065548117883,
|
||||
0.9990972789408072,
|
||||
1.0839295375488778
|
||||
],
|
||||
[
|
||||
0.4,
|
||||
0.8049378423020082,
|
||||
0.9991798679155696,
|
||||
1.0843313360801736
|
||||
],
|
||||
[
|
||||
0.5,
|
||||
0.7783013127010345,
|
||||
0.9995757318625371,
|
||||
1.0927949851904588
|
||||
],
|
||||
[
|
||||
0.6,
|
||||
0.7494218899417543,
|
||||
0.99990720764609,
|
||||
1.1004481450175467
|
||||
],
|
||||
[
|
||||
0.7,
|
||||
0.7208206554811788,
|
||||
1.0,
|
||||
1.103618542638603
|
||||
],
|
||||
[
|
||||
0.8,
|
||||
0.6899243675562896,
|
||||
1.0,
|
||||
1.1099255135872232
|
||||
],
|
||||
[
|
||||
0.9,
|
||||
0.6402851430061723,
|
||||
1.0,
|
||||
1.1104694596707287
|
||||
],
|
||||
[
|
||||
0.95,
|
||||
0.5873424324089368,
|
||||
1.0,
|
||||
1.112976807792225
|
||||
],
|
||||
[
|
||||
0.98,
|
||||
0.4996783447796227,
|
||||
1.0,
|
||||
1.1147969880866666
|
||||
]
|
||||
],
|
||||
"pair": {
|
||||
"edges": [
|
||||
0.0,
|
||||
0.5,
|
||||
1.0,
|
||||
1.5,
|
||||
2.0,
|
||||
2.5,
|
||||
3.0,
|
||||
4.0,
|
||||
6.0
|
||||
],
|
||||
"n_true": [
|
||||
2071.0,
|
||||
5881.0,
|
||||
8150.0,
|
||||
9016.0,
|
||||
8526.0,
|
||||
7056.0,
|
||||
9418.0,
|
||||
6208.0,
|
||||
1189.0
|
||||
],
|
||||
"n_match": [
|
||||
879.0,
|
||||
2570.0,
|
||||
4252.0,
|
||||
6749.0,
|
||||
7847.0,
|
||||
6650.0,
|
||||
8874.0,
|
||||
5838.0,
|
||||
1105.0
|
||||
],
|
||||
"efficiency": [
|
||||
0.4244326412361178,
|
||||
0.437000510117327,
|
||||
0.5217177914110429,
|
||||
0.7485581188997338,
|
||||
0.9203612479474549,
|
||||
0.9424603174603174,
|
||||
0.9422382671480144,
|
||||
0.9403994845360825,
|
||||
0.9293523969722456
|
||||
]
|
||||
}
|
||||
},
|
||||
"10%": {
|
||||
"occupancy": 0.1,
|
||||
"summary": {
|
||||
"n_true": 459644,
|
||||
"n_pred": 296422,
|
||||
"n_match": 296313,
|
||||
"efficiency": 0.6446576045809366,
|
||||
"purity": 0.9996322810047837,
|
||||
"f1": 0.7838283959336884,
|
||||
"rms_x_um": 1.504689585816301,
|
||||
"rms_y_um": 1.5027888173805302,
|
||||
"rms_1d_um": 1.503747791841089,
|
||||
"sigma68_1d_um": 0.8647918701171875,
|
||||
"bias_x_um": 0.05110033320099986,
|
||||
"bias_y_um": 0.041113979922734765,
|
||||
"energy_bias_keV": 0.0010869613583709497,
|
||||
"energy_rms_keV": 0.07619505041448714,
|
||||
"energy_sigma68_keV": 0.075958251953125,
|
||||
"subpixel_nonuniformity": 0.3057987053821632
|
||||
},
|
||||
"roc": [
|
||||
[
|
||||
0.05,
|
||||
0.6654160478709084,
|
||||
0.9992044758017189,
|
||||
1.4912192081439517
|
||||
],
|
||||
[
|
||||
0.1,
|
||||
0.6654160478709084,
|
||||
0.9992044758017189,
|
||||
1.4912192081439517
|
||||
],
|
||||
[
|
||||
0.2,
|
||||
0.6654160478709084,
|
||||
0.9992044758017189,
|
||||
1.4912192081439517
|
||||
],
|
||||
[
|
||||
0.3,
|
||||
0.6653639387544185,
|
||||
0.999204413548446,
|
||||
1.491247660189543
|
||||
],
|
||||
[
|
||||
0.4,
|
||||
0.6626282101386971,
|
||||
0.9992403902822343,
|
||||
1.4930164576670335
|
||||
],
|
||||
[
|
||||
0.5,
|
||||
0.6446766195079162,
|
||||
0.9997171755262555,
|
||||
1.5047942652142676
|
||||
],
|
||||
[
|
||||
0.6,
|
||||
0.6240761487888973,
|
||||
0.9999165089613715,
|
||||
1.508506729948408
|
||||
],
|
||||
[
|
||||
0.7,
|
||||
0.6014868467905127,
|
||||
0.9999711228865562,
|
||||
1.4978212257870458
|
||||
],
|
||||
[
|
||||
0.8,
|
||||
0.5729484206595277,
|
||||
0.9999848420542048,
|
||||
1.478323164043431
|
||||
],
|
||||
[
|
||||
0.9,
|
||||
0.5211606437212857,
|
||||
1.0,
|
||||
1.4475402949684142
|
||||
],
|
||||
[
|
||||
0.95,
|
||||
0.46470041600444667,
|
||||
1.0,
|
||||
1.4131163405725333
|
||||
],
|
||||
[
|
||||
0.98,
|
||||
0.3782427068949046,
|
||||
1.0,
|
||||
1.3692874407279128
|
||||
]
|
||||
],
|
||||
"pair": {
|
||||
"edges": [
|
||||
0.0,
|
||||
0.5,
|
||||
1.0,
|
||||
1.5,
|
||||
2.0,
|
||||
2.5,
|
||||
3.0,
|
||||
4.0,
|
||||
6.0
|
||||
],
|
||||
"n_true": [
|
||||
8521.0,
|
||||
21685.0,
|
||||
25993.0,
|
||||
22696.0,
|
||||
16020.0,
|
||||
9724.0,
|
||||
8002.0,
|
||||
2362.0,
|
||||
140.0
|
||||
],
|
||||
"n_match": [
|
||||
3267.0,
|
||||
8495.0,
|
||||
12545.0,
|
||||
16713.0,
|
||||
14588.0,
|
||||
9070.0,
|
||||
7340.0,
|
||||
2093.0,
|
||||
120.0
|
||||
],
|
||||
"efficiency": [
|
||||
0.3834057035559207,
|
||||
0.39174544616094076,
|
||||
0.4826299388296849,
|
||||
0.7363852661261896,
|
||||
0.9106117353308365,
|
||||
0.932743726861374,
|
||||
0.9172706823294177,
|
||||
0.8861134631668078,
|
||||
0.8571428571428571
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,734 @@
|
||||
{
|
||||
"train_loss": [
|
||||
0.23993744641510628,
|
||||
0.13196626334205636,
|
||||
0.11608033124735159,
|
||||
0.10756625584152744,
|
||||
0.10190933465703193,
|
||||
0.09787552357674154,
|
||||
0.09481275513402426,
|
||||
0.09245659170817414,
|
||||
0.0903575554362865,
|
||||
0.08874685361806459,
|
||||
0.0873924339768599,
|
||||
0.08617739734044069,
|
||||
0.08512466338839832,
|
||||
0.08428180176394981,
|
||||
0.08355168168102028,
|
||||
0.08280495518426885,
|
||||
0.08215654689099007,
|
||||
0.08170365822067129,
|
||||
0.08109293564788306,
|
||||
0.08064124489097738,
|
||||
0.08023965582172034,
|
||||
0.0798451739940852,
|
||||
0.07947116269627656,
|
||||
0.0790973027398772,
|
||||
0.07883267661232576,
|
||||
0.078509494558915,
|
||||
0.07818648193663696,
|
||||
0.07799587040948766,
|
||||
0.0776730109097609,
|
||||
0.07739392428667848,
|
||||
0.07722281022126545,
|
||||
0.07699475143196234,
|
||||
0.07687328443360558,
|
||||
0.07667010834911717,
|
||||
0.07647448817910099,
|
||||
0.0763024338376942,
|
||||
0.07610494880405282,
|
||||
0.07602332044977261,
|
||||
0.07588070763022567,
|
||||
0.07576910217104751,
|
||||
0.07558895031282462,
|
||||
0.07540235324119682,
|
||||
0.07532636232857007,
|
||||
0.07520397323140976,
|
||||
0.07502932811559455,
|
||||
0.07500694960896462,
|
||||
0.07489564324646647,
|
||||
0.07470230517258894,
|
||||
0.07468266000329113,
|
||||
0.07455802075127527,
|
||||
0.07448664903958808,
|
||||
0.07439325880279155,
|
||||
0.07426496459173164,
|
||||
0.07423872732842618,
|
||||
0.07412104704591228,
|
||||
0.07319306893117146,
|
||||
0.07315842396199003,
|
||||
0.07315353711265891,
|
||||
0.07308529504239877,
|
||||
0.07304423302412033,
|
||||
0.07295355107734654,
|
||||
0.07292400597094727,
|
||||
0.07291898736481733,
|
||||
0.0728418159446696,
|
||||
0.07279567202610801,
|
||||
0.0727923296256788,
|
||||
0.07273335824049651,
|
||||
0.07272118880247484,
|
||||
0.07269519763097183,
|
||||
0.0726498324531374,
|
||||
0.07262815370471908,
|
||||
0.07259573691237316,
|
||||
0.07256286855282117,
|
||||
0.07255131185150197,
|
||||
0.07250253140544688,
|
||||
0.07249244097361825,
|
||||
0.07245224617270549,
|
||||
0.07246539340202429,
|
||||
0.07238171729105132,
|
||||
0.07233716793986497,
|
||||
0.07235877035362616,
|
||||
0.07234092938575572,
|
||||
0.07226683528598879,
|
||||
0.0722777515474862,
|
||||
0.07225812967616187,
|
||||
0.07224044434352517,
|
||||
0.07217869057599356,
|
||||
0.0722048584224702,
|
||||
0.07215245076819952,
|
||||
0.07215746614600958,
|
||||
0.0721534180316752,
|
||||
0.07210610139808889,
|
||||
0.07205967306931729,
|
||||
0.07205103477711611,
|
||||
0.07200603136989579,
|
||||
0.071978636726085,
|
||||
0.072040851431697,
|
||||
0.07196603934881908,
|
||||
0.07196702520296439,
|
||||
0.07194990338707938,
|
||||
0.07192121945488542,
|
||||
0.07187795462514192,
|
||||
0.07188086827129539,
|
||||
0.07186853657441816,
|
||||
0.07180670765700692,
|
||||
0.07186382735424388,
|
||||
0.07178202015422325,
|
||||
0.0717921020699667,
|
||||
0.07176873955394568,
|
||||
0.07174791631029408,
|
||||
0.07173027876633335,
|
||||
0.07173992375363153,
|
||||
0.07170136809237738,
|
||||
0.0711954400627183,
|
||||
0.0711862329262425,
|
||||
0.0711553716274692,
|
||||
0.07116745289101035,
|
||||
0.07114298475494761,
|
||||
0.07113313009383966,
|
||||
0.07113049572916143
|
||||
],
|
||||
"val_loss": [
|
||||
0.1447843129634857,
|
||||
0.12180081671476364,
|
||||
0.11107439863681794,
|
||||
0.10671789038181305,
|
||||
0.10051913315057755,
|
||||
0.09682093042135238,
|
||||
0.09403118115663528,
|
||||
0.0919740365743637,
|
||||
0.08973157322406769,
|
||||
0.0881431828737259,
|
||||
0.08681886410713195,
|
||||
0.08582492661476135,
|
||||
0.08494884830713272,
|
||||
0.08402856802940369,
|
||||
0.08506861454248428,
|
||||
0.08367731243371963,
|
||||
0.08199280154705048,
|
||||
0.08202545255422593,
|
||||
0.08186581325531006,
|
||||
0.08074425691366195,
|
||||
0.08054110908508301,
|
||||
0.08009980624914169,
|
||||
0.07967528188228608,
|
||||
0.07916471648216247,
|
||||
0.0788530655503273,
|
||||
0.07914198207855225,
|
||||
0.07845976740121842,
|
||||
0.07806322836875916,
|
||||
0.07768297368288041,
|
||||
0.0778607325553894,
|
||||
0.07737875044345856,
|
||||
0.07682216674089432,
|
||||
0.07743264657258987,
|
||||
0.07693758219480515,
|
||||
0.07715221554040909,
|
||||
0.07661716121435165,
|
||||
0.07610375595092773,
|
||||
0.07629099428653717,
|
||||
0.0761166660785675,
|
||||
0.07626022684574127,
|
||||
0.07677691966295243,
|
||||
0.0755103154182434,
|
||||
0.07530945605039596,
|
||||
0.07527553778886795,
|
||||
0.07565634047985077,
|
||||
0.07560070466995239,
|
||||
0.07543402361869812,
|
||||
0.07513380587100983,
|
||||
0.07498476415872574,
|
||||
0.07448901307582856,
|
||||
0.07489384853839874,
|
||||
0.07509817326068878,
|
||||
0.07472086840867996,
|
||||
0.07455998528003692,
|
||||
0.07458109045028687,
|
||||
0.0736760407090187,
|
||||
0.0739127681851387,
|
||||
0.07348479974269867,
|
||||
0.0737179503440857,
|
||||
0.07337816250324249,
|
||||
0.07349218189716339,
|
||||
0.0736083345413208,
|
||||
0.0733383971452713,
|
||||
0.07308566790819168,
|
||||
0.07324155068397523,
|
||||
0.07341372239589691,
|
||||
0.073162602186203,
|
||||
0.07318145686388015,
|
||||
0.07304516649246216,
|
||||
0.07317802047729492,
|
||||
0.07307149517536163,
|
||||
0.07285879522562028,
|
||||
0.07301505696773529,
|
||||
0.0728074852824211,
|
||||
0.0728095685839653,
|
||||
0.07308397686481476,
|
||||
0.07293559992313385,
|
||||
0.07273350220918655,
|
||||
0.07274707239866257,
|
||||
0.07276939767599105,
|
||||
0.07303122365474701,
|
||||
0.0727171242237091,
|
||||
0.07276431161165238,
|
||||
0.07267237484455108,
|
||||
0.07290990674495697,
|
||||
0.07271710741519928,
|
||||
0.07273158556222915,
|
||||
0.07252232605218888,
|
||||
0.07247878211736679,
|
||||
0.07271854496002197,
|
||||
0.07257393556833268,
|
||||
0.07263265854120254,
|
||||
0.07244504135847092,
|
||||
0.07236862510442733,
|
||||
0.07256510639190673,
|
||||
0.07235708618164062,
|
||||
0.07260376578569412,
|
||||
0.07234354418516159,
|
||||
0.07233692508935928,
|
||||
0.07253305220603942,
|
||||
0.07241593664884567,
|
||||
0.07230457752943038,
|
||||
0.07217080211639404,
|
||||
0.07222512978315353,
|
||||
0.07210155928134918,
|
||||
0.07223321187496186,
|
||||
0.0721174014210701,
|
||||
0.07204049426317215,
|
||||
0.07205111521482467,
|
||||
0.07227177548408509,
|
||||
0.07243644344806671,
|
||||
0.07211517387628555,
|
||||
0.07222532117366791,
|
||||
0.07178664696216583,
|
||||
0.07166123247146607,
|
||||
0.07161745244264603,
|
||||
0.07157982540130615,
|
||||
0.07163847053050995,
|
||||
0.07152747827768326,
|
||||
0.07152942806482315
|
||||
],
|
||||
"efficiency": [
|
||||
0.7528893166175447,
|
||||
0.7789511673268773,
|
||||
0.7703755896783728,
|
||||
0.770607594284094,
|
||||
0.7880852745817473,
|
||||
0.7913505245881918,
|
||||
0.787389260764584,
|
||||
0.7842185311530628,
|
||||
0.7761757048213994,
|
||||
0.7814001048317107,
|
||||
0.7793034706170463,
|
||||
0.7828436890450863,
|
||||
0.7848200245753026,
|
||||
0.7847942462857781,
|
||||
0.7884719489246157,
|
||||
0.7829811732558839,
|
||||
0.7834537752305009,
|
||||
0.7854215179975425,
|
||||
0.7875267449753818,
|
||||
0.7811681002259897,
|
||||
0.7830499153612828,
|
||||
0.7835998522044734,
|
||||
0.7836256304939979,
|
||||
0.7808759462780447,
|
||||
0.7834881462832003,
|
||||
0.7834881462832003,
|
||||
0.7828179107555616,
|
||||
0.7847083186540296,
|
||||
0.7819844127276008,
|
||||
0.77849575087861,
|
||||
0.7824827929917424,
|
||||
0.7801369686450071,
|
||||
0.7765194153483936,
|
||||
0.778676198905282,
|
||||
0.7806353489091488,
|
||||
0.7815633673320329,
|
||||
0.7851723278654718,
|
||||
0.7842958660216366,
|
||||
0.779561253512292,
|
||||
0.7792862850906966,
|
||||
0.7842099383898881,
|
||||
0.7804806791720014,
|
||||
0.778968352853227,
|
||||
0.7857652285245367,
|
||||
0.7806697199618481,
|
||||
0.7795956245649913,
|
||||
0.7819414489117266,
|
||||
0.7791745791694236,
|
||||
0.7861261245778806,
|
||||
0.7856019660242144,
|
||||
0.7818641140431528,
|
||||
0.7830671008876324,
|
||||
0.7839607482578173,
|
||||
0.7856621153664384,
|
||||
0.7824226436495184,
|
||||
0.7838404495733693,
|
||||
0.7830499153612828,
|
||||
0.7849661015492752,
|
||||
0.7798620002234118,
|
||||
0.7815461818056832,
|
||||
0.7844075719429097,
|
||||
0.7840896397054401,
|
||||
0.7854129252343676,
|
||||
0.7821476752279231,
|
||||
0.778727755484331,
|
||||
0.7834194041778014,
|
||||
0.7814001048317107,
|
||||
0.7830069515454084,
|
||||
0.782388272596819,
|
||||
0.7829639877295342,
|
||||
0.7832217706247798,
|
||||
0.7836771870730471,
|
||||
0.7837373364152711,
|
||||
0.7827835397028623,
|
||||
0.7851895133918214,
|
||||
0.7849403232597506,
|
||||
0.7816063311479072,
|
||||
0.7836170377308231,
|
||||
0.7823624943072944,
|
||||
0.7835740739149488,
|
||||
0.7788996107478282,
|
||||
0.7836514087835225,
|
||||
0.781090765357416,
|
||||
0.7827577614133376,
|
||||
0.7835139245727248,
|
||||
0.7836170377308231,
|
||||
0.780970466672968,
|
||||
0.7841669745740137,
|
||||
0.7794065837751446,
|
||||
0.7810478015415417,
|
||||
0.7818039647009288,
|
||||
0.7809275028570938,
|
||||
0.7837803002311453,
|
||||
0.78320458509843,
|
||||
0.7834537752305009,
|
||||
0.7793206561433961,
|
||||
0.7820101910171253,
|
||||
0.7850090653651495,
|
||||
0.7807814258831213,
|
||||
0.7820445620698248,
|
||||
0.7807040910145475,
|
||||
0.7836256304939979,
|
||||
0.7817438153587049,
|
||||
0.7823624943072944,
|
||||
0.7807814258831213,
|
||||
0.7823109377282452,
|
||||
0.7792175429852978,
|
||||
0.7797073304862645,
|
||||
0.7815461818056832,
|
||||
0.7815977383847323,
|
||||
0.7802486745662803,
|
||||
0.7853527758921436,
|
||||
0.7817438153587049,
|
||||
0.7798620002234118,
|
||||
0.7827749469396874,
|
||||
0.7846739476013301,
|
||||
0.779793258118013,
|
||||
0.784270087732112,
|
||||
0.7812368423313885,
|
||||
0.782680426544764
|
||||
],
|
||||
"purity": [
|
||||
0.999475275195346,
|
||||
0.9992614557038768,
|
||||
0.9994648948741388,
|
||||
0.9995207525299808,
|
||||
0.9993244494808068,
|
||||
0.9992947048611112,
|
||||
0.9993347510769398,
|
||||
0.9994305550992696,
|
||||
0.9994799504293175,
|
||||
0.9993955512572534,
|
||||
0.9995260976900018,
|
||||
0.9993747394747812,
|
||||
0.9994200551494726,
|
||||
0.99937629255162,
|
||||
0.9993900845168598,
|
||||
0.999374849196078,
|
||||
0.9994190443828168,
|
||||
0.9993767903610242,
|
||||
0.9993457638207393,
|
||||
0.9995052498488264,
|
||||
0.9994516281161232,
|
||||
0.9994081997216346,
|
||||
0.9994082191780822,
|
||||
0.9994061365885846,
|
||||
0.9994300245527885,
|
||||
0.9994628900897741,
|
||||
0.9994076089341349,
|
||||
0.999343415552297,
|
||||
0.9994399051133368,
|
||||
0.9994484219351565,
|
||||
0.9994183238948154,
|
||||
0.9994055743912641,
|
||||
0.9995022894684451,
|
||||
0.9994705960206468,
|
||||
0.999526905854265,
|
||||
0.9994945166040307,
|
||||
0.9993656626637794,
|
||||
0.9994196677871823,
|
||||
0.9994822077779002,
|
||||
0.9994599955918008,
|
||||
0.9994414937304934,
|
||||
0.9995378114270622,
|
||||
0.9995258939104932,
|
||||
0.9994098296156242,
|
||||
0.9994389624104815,
|
||||
0.9994491996871454,
|
||||
0.9994179214303757,
|
||||
0.9995150018738564,
|
||||
0.9993227670427858,
|
||||
0.9994097070397902,
|
||||
0.9994288413167405,
|
||||
0.9994187576767855,
|
||||
0.9994413163026094,
|
||||
0.9993551348751804,
|
||||
0.9994511887252212,
|
||||
0.9994740821089307,
|
||||
0.9994297057501015,
|
||||
0.9994201630107762,
|
||||
0.9994714005682444,
|
||||
0.999439591231251,
|
||||
0.9994197503831838,
|
||||
0.9994085691755016,
|
||||
0.9993767835470856,
|
||||
0.9995058691761192,
|
||||
0.9995367715180659,
|
||||
0.9994409304670971,
|
||||
0.9994724405121723,
|
||||
0.9994625601877749,
|
||||
0.9994072838232388,
|
||||
0.9993529140801509,
|
||||
0.9994407894736842,
|
||||
0.9994192099063065,
|
||||
0.9994083034745734,
|
||||
0.9994514416114452,
|
||||
0.9993984666367722,
|
||||
0.999420143979344,
|
||||
0.9995055271081028,
|
||||
0.9994410713894307,
|
||||
0.9993962943449245,
|
||||
0.9994300870213279,
|
||||
0.9995368736767819,
|
||||
0.9993972866942819,
|
||||
0.999472231690288,
|
||||
0.9994843211691646,
|
||||
0.9994300432947882,
|
||||
0.9994410713894307,
|
||||
0.9994941330430097,
|
||||
0.9994414631475195,
|
||||
0.9995371747826375,
|
||||
0.9994941831057157,
|
||||
0.9994617336570255,
|
||||
0.9994611298677019,
|
||||
0.9994083358899066,
|
||||
0.9994188596491228,
|
||||
0.9994299995615381,
|
||||
0.9994710335783477,
|
||||
0.9994838284553292,
|
||||
0.9994311282258859,
|
||||
0.9994830165434706,
|
||||
0.9994509235465946,
|
||||
0.9994609757439085,
|
||||
0.9994191717169503,
|
||||
0.9994397328294591,
|
||||
0.999407264305237,
|
||||
0.9995379893737556,
|
||||
0.9994401387577667,
|
||||
0.9995150286022904,
|
||||
0.9995153330983433,
|
||||
0.9994725390650755,
|
||||
0.9995055216746332,
|
||||
0.9995266715100279,
|
||||
0.9994095198521613,
|
||||
0.9995165950714671,
|
||||
0.9994934143870314,
|
||||
0.9994624009830382,
|
||||
0.9994090093245196,
|
||||
0.9994933697519714,
|
||||
0.9994305925122915,
|
||||
0.999472330321219,
|
||||
0.9994733030482587
|
||||
],
|
||||
"rms_1d_um": [
|
||||
1.9957276837545026,
|
||||
1.7052481326275368,
|
||||
1.607867353051229,
|
||||
1.5386362101751911,
|
||||
1.4629472412433182,
|
||||
1.419914456951616,
|
||||
1.3875089916354204,
|
||||
1.3591751371155003,
|
||||
1.326955817601164,
|
||||
1.315046204610855,
|
||||
1.2944686631475242,
|
||||
1.2741938167909073,
|
||||
1.2518345619757278,
|
||||
1.2519973544040521,
|
||||
1.2741819383148978,
|
||||
1.2461789741144633,
|
||||
1.2332135193270557,
|
||||
1.2172420617410113,
|
||||
1.2288223278707853,
|
||||
1.2137821315364055,
|
||||
1.204417753396746,
|
||||
1.2135477588750274,
|
||||
1.2047470100444082,
|
||||
1.1973607131520918,
|
||||
1.196213916650463,
|
||||
1.194062803180352,
|
||||
1.1883971038278132,
|
||||
1.187188264079335,
|
||||
1.1885839781315253,
|
||||
1.1753985039433763,
|
||||
1.1746504828554816,
|
||||
1.1702461369570036,
|
||||
1.179932844769689,
|
||||
1.1743969547180375,
|
||||
1.177318024941057,
|
||||
1.1702283508280227,
|
||||
1.1631606694457637,
|
||||
1.1648540738437512,
|
||||
1.1673295463691271,
|
||||
1.168178838019741,
|
||||
1.1621849474883104,
|
||||
1.1537410372846353,
|
||||
1.1528237603597007,
|
||||
1.1518643664912749,
|
||||
1.1614324534698262,
|
||||
1.153850993134394,
|
||||
1.1631865967283666,
|
||||
1.1556078817047648,
|
||||
1.146499683802479,
|
||||
1.1463666684110478,
|
||||
1.1523505848087052,
|
||||
1.14384742248673,
|
||||
1.1469606929660685,
|
||||
1.150249619593332,
|
||||
1.1508898901234208,
|
||||
1.1458063869532469,
|
||||
1.147080695841803,
|
||||
1.1317223721682037,
|
||||
1.138034884854095,
|
||||
1.1380879723439374,
|
||||
1.1386982084711657,
|
||||
1.13600211390625,
|
||||
1.1397208783193582,
|
||||
1.136983103621553,
|
||||
1.1425336955942123,
|
||||
1.1428391395149426,
|
||||
1.1382956332255045,
|
||||
1.1302274503514875,
|
||||
1.1297301429781763,
|
||||
1.127794394977013,
|
||||
1.1339898038771516,
|
||||
1.1304566907200795,
|
||||
1.1279934435712042,
|
||||
1.12812557259591,
|
||||
1.1295535353868382,
|
||||
1.1225942721027018,
|
||||
1.1339557244653264,
|
||||
1.123414887240159,
|
||||
1.1365932894609592,
|
||||
1.1325205470753563,
|
||||
1.1213523879628808,
|
||||
1.1287775216512113,
|
||||
1.1324143040551773,
|
||||
1.1302923364599637,
|
||||
1.1260996057335697,
|
||||
1.1214342597589066,
|
||||
1.1221972484155256,
|
||||
1.1189983160600643,
|
||||
1.1268814581388924,
|
||||
1.1323275730408926,
|
||||
1.1268825173018757,
|
||||
1.1230667281991895,
|
||||
1.1221255234378922,
|
||||
1.1236895497601695,
|
||||
1.1172322185277896,
|
||||
1.1200865175757602,
|
||||
1.122599075223511,
|
||||
1.1191134799003264,
|
||||
1.1184832079599694,
|
||||
1.1290631628817986,
|
||||
1.1190859962749526,
|
||||
1.11778158117159,
|
||||
1.1213144900355483,
|
||||
1.124063858296662,
|
||||
1.1204100766073202,
|
||||
1.1224352881906237,
|
||||
1.1167503432162673,
|
||||
1.125525359080101,
|
||||
1.1167700528311282,
|
||||
1.1260481804297091,
|
||||
1.1178404242441295,
|
||||
1.1128263993848184,
|
||||
1.113918510834081,
|
||||
1.1147003843523995,
|
||||
1.1115423619213338,
|
||||
1.11573074170728,
|
||||
1.1153441908738733,
|
||||
1.1124969441390817,
|
||||
1.1192881645507677,
|
||||
1.1111686110256012
|
||||
],
|
||||
"sigma68_1d_um": [
|
||||
1.136922836303711,
|
||||
0.9791268849372863,
|
||||
0.9145471787452696,
|
||||
0.9118080139160156,
|
||||
0.8578772139549252,
|
||||
0.8295297622680664,
|
||||
0.8217811584472656,
|
||||
0.8090757513046263,
|
||||
0.7811546325683594,
|
||||
0.7753372192382812,
|
||||
0.7677555084228516,
|
||||
0.7633209228515625,
|
||||
0.7532179975509639,
|
||||
0.7490158081054688,
|
||||
0.7757356321811676,
|
||||
0.7672293353080749,
|
||||
0.7415539669990537,
|
||||
0.7388114929199219,
|
||||
0.7558584213256836,
|
||||
0.7328510284423828,
|
||||
0.7368087768554688,
|
||||
0.7319211959838867,
|
||||
0.7253408432006836,
|
||||
0.7309436798095703,
|
||||
0.7240888905525208,
|
||||
0.7355690002441406,
|
||||
0.7283923172950745,
|
||||
0.7188796997070312,
|
||||
0.7212638854980469,
|
||||
0.7211685180664062,
|
||||
0.7194218039512632,
|
||||
0.7114887237548828,
|
||||
0.721362826824188,
|
||||
0.7144180607795713,
|
||||
0.7258976221084595,
|
||||
0.7123145985603332,
|
||||
0.708557459115982,
|
||||
0.7151126861572266,
|
||||
0.7138252258300781,
|
||||
0.7142543792724609,
|
||||
0.7302761077880859,
|
||||
0.7109642028808594,
|
||||
0.7056151497364044,
|
||||
0.7036361837387082,
|
||||
0.7135629653930664,
|
||||
0.7150155591964719,
|
||||
0.7172107696533203,
|
||||
0.7133007049560547,
|
||||
0.7050911688804624,
|
||||
0.7032394409179688,
|
||||
0.7080078125,
|
||||
0.7175922393798828,
|
||||
0.7073402404785156,
|
||||
0.7059208810329436,
|
||||
0.7112503051757812,
|
||||
0.6974570918083188,
|
||||
0.703470892906189,
|
||||
0.6975650787353516,
|
||||
0.7024765014648438,
|
||||
0.695037841796875,
|
||||
0.6990194320678711,
|
||||
0.7006645202636719,
|
||||
0.6958484649658203,
|
||||
0.6944295620918272,
|
||||
0.6971134591102598,
|
||||
0.6967544555664062,
|
||||
0.6978034973144531,
|
||||
0.695037841796875,
|
||||
0.6933689117431641,
|
||||
0.6963491439819336,
|
||||
0.6952524185180664,
|
||||
0.6919384002685547,
|
||||
0.6938934326171875,
|
||||
0.6922245025634766,
|
||||
0.6925344467163086,
|
||||
0.6983280181884766,
|
||||
0.6984710693359375,
|
||||
0.6919846677780152,
|
||||
0.6938605761528015,
|
||||
0.6942783188819884,
|
||||
0.6996631622314453,
|
||||
0.6937503814697266,
|
||||
0.6947517395019531,
|
||||
0.6936073303222656,
|
||||
0.6963729858398438,
|
||||
0.6979465484619141,
|
||||
0.6951332092285156,
|
||||
0.6941241729259491,
|
||||
0.6917715072631836,
|
||||
0.6977422571182251,
|
||||
0.6914138793945312,
|
||||
0.6928348565101623,
|
||||
0.6919384002685547,
|
||||
0.6921394133567811,
|
||||
0.6954669952392578,
|
||||
0.6922006607055664,
|
||||
0.6928920745849609,
|
||||
0.6909171366691589,
|
||||
0.6928443908691406,
|
||||
0.6922006607055664,
|
||||
0.6932782983779904,
|
||||
0.6922483444213867,
|
||||
0.6909519720077515,
|
||||
0.6924539065361023,
|
||||
0.6911993026733398,
|
||||
0.6916999816894531,
|
||||
0.6906032562255859,
|
||||
0.6901264190673828,
|
||||
0.6897427773475646,
|
||||
0.6913661956787109,
|
||||
0.6920814514160156,
|
||||
0.6891675257682799,
|
||||
0.6932094836235047,
|
||||
0.6890773773193359,
|
||||
0.687408447265625,
|
||||
0.6854057312011719,
|
||||
0.6884750032424926,
|
||||
0.6864724326133727,
|
||||
0.6877899169921875,
|
||||
0.6863389420509337
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 54 KiB |
@@ -0,0 +1,64 @@
|
||||
experiment:
|
||||
name: 12keV_Moench040
|
||||
results_dir: Results
|
||||
data:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/GridBased/12keV_Moench040_150V
|
||||
train_shards:
|
||||
- 0
|
||||
- 11
|
||||
val_shards:
|
||||
- 0
|
||||
- 1
|
||||
max_train_frames: null
|
||||
max_val_frames: 8000
|
||||
input_scale: 12.0
|
||||
energy_scale: 12.0
|
||||
augment: true
|
||||
batch_size_train: 256
|
||||
batch_size_val: 512
|
||||
num_workers: 8
|
||||
model:
|
||||
channels:
|
||||
- 32
|
||||
- 64
|
||||
- 64
|
||||
- 64
|
||||
predict_energy: true
|
||||
norm: none
|
||||
prior_prob: 0.01
|
||||
loss:
|
||||
w_obj: 1.0
|
||||
w_off: 1.0
|
||||
w_ene: 0.1
|
||||
focal_alpha: 0.25
|
||||
focal_gamma: 2.0
|
||||
smooth_l1_beta_offset: 0.01
|
||||
smooth_l1_beta_energy: 0.02
|
||||
training:
|
||||
epochs: 1000
|
||||
lr: 0.001
|
||||
weight_decay: 0.0
|
||||
scheduler_factor: 0.5
|
||||
scheduler_patience: 4
|
||||
amp: true
|
||||
seed: 0
|
||||
checkpoint_epochs:
|
||||
- 20
|
||||
- 40
|
||||
- 60
|
||||
- 80
|
||||
- 100
|
||||
- 200
|
||||
- 300
|
||||
- 400
|
||||
- 500
|
||||
- 600
|
||||
- 700
|
||||
- 800
|
||||
- 900
|
||||
- 1000
|
||||
eval:
|
||||
threshold: 0.3
|
||||
nms_kernel: 3
|
||||
match_radius: 1.0
|
||||
pixel_size_um: 25.0
|
||||
|
After Width: | Height: | Size: 115 KiB |
|
After Width: | Height: | Size: 127 KiB |
|
After Width: | Height: | Size: 232 KiB |
|
After Width: | Height: | Size: 63 KiB |
@@ -0,0 +1,312 @@
|
||||
{
|
||||
"0.5%": {
|
||||
"occupancy": 0.005,
|
||||
"n_clusters": {
|
||||
"1": 7967,
|
||||
"2": 447,
|
||||
"3": 26
|
||||
},
|
||||
"grid": {
|
||||
"n_true": 5827,
|
||||
"n_pred": 5810,
|
||||
"n_match": 5805,
|
||||
"efficiency": 0.9962244722841943,
|
||||
"purity": 0.9991394148020654,
|
||||
"f1": 0.9976798143851509,
|
||||
"rms_x_um": 0.7751722440025511,
|
||||
"rms_y_um": 0.8334788377150387,
|
||||
"rms_1d_um": 0.804855703165607,
|
||||
"sigma68_1d_um": 0.5931564760208129,
|
||||
"bias_x_um": -0.008547874897538743,
|
||||
"bias_y_um": -0.004963172498599504,
|
||||
"energy_bias_keV": 4.7871657838911765e-05,
|
||||
"energy_rms_keV": 0.07488460080343108,
|
||||
"energy_sigma68_keV": 0.0749839256286621,
|
||||
"subpixel_nonuniformity": 0.05240391513816991
|
||||
},
|
||||
"cluster+dl": {
|
||||
"n_true": 5827,
|
||||
"n_pred": 5822,
|
||||
"n_match": 5806,
|
||||
"efficiency": 0.9963960871803672,
|
||||
"purity": 0.9972518035039505,
|
||||
"f1": 0.996823761696283,
|
||||
"rms_x_um": 0.8350069908627891,
|
||||
"rms_y_um": 0.9438987529996069,
|
||||
"rms_1d_um": 0.8911333851614491,
|
||||
"sigma68_1d_um": 0.5948124534264206,
|
||||
"bias_x_um": 0.009228541323870772,
|
||||
"bias_y_um": -0.001344026449815599,
|
||||
"energy_bias_keV": -0.0020763391960582937,
|
||||
"energy_rms_keV": 0.0751517504762937,
|
||||
"energy_sigma68_keV": 0.07571983337402344,
|
||||
"subpixel_nonuniformity": 0.03405747622316486
|
||||
},
|
||||
"cluster+eta": {
|
||||
"n_true": 5827,
|
||||
"n_pred": 5085,
|
||||
"n_match": 5078,
|
||||
"efficiency": 0.8714604427664321,
|
||||
"purity": 0.9986234021632252,
|
||||
"f1": 0.9307184750733137,
|
||||
"rms_x_um": 1.082732698577549,
|
||||
"rms_y_um": 1.707804172101413,
|
||||
"rms_1d_um": 1.4298435589774205,
|
||||
"sigma68_1d_um": 1.1606203316388393,
|
||||
"bias_x_um": -0.0503576774662195,
|
||||
"bias_y_um": -0.0505550725893291,
|
||||
"energy_bias_keV": -0.001967431617186923,
|
||||
"energy_rms_keV": 0.07507446519993481,
|
||||
"energy_sigma68_keV": 0.07571983337402344,
|
||||
"subpixel_nonuniformity": 0.0
|
||||
}
|
||||
},
|
||||
"1%": {
|
||||
"occupancy": 0.01,
|
||||
"n_clusters": {
|
||||
"1": 13719,
|
||||
"2": 1525,
|
||||
"3": 171
|
||||
},
|
||||
"grid": {
|
||||
"n_true": 11517,
|
||||
"n_pred": 11449,
|
||||
"n_match": 11437,
|
||||
"efficiency": 0.9930537466354086,
|
||||
"purity": 0.9989518735260722,
|
||||
"f1": 0.9959940782025604,
|
||||
"rms_x_um": 0.8600146625936027,
|
||||
"rms_y_um": 0.8508395013933928,
|
||||
"rms_1d_um": 0.8554812700460162,
|
||||
"sigma68_1d_um": 0.6103871524333954,
|
||||
"bias_x_um": -0.016917289736555038,
|
||||
"bias_y_um": 1.3734552840872996e-05,
|
||||
"energy_bias_keV": 0.001381515695715822,
|
||||
"energy_rms_keV": 0.07480540928892503,
|
||||
"energy_sigma68_keV": 0.07508318786621093,
|
||||
"subpixel_nonuniformity": 0.0
|
||||
},
|
||||
"cluster+dl": {
|
||||
"n_true": 11517,
|
||||
"n_pred": 11389,
|
||||
"n_match": 11317,
|
||||
"efficiency": 0.9826343665885213,
|
||||
"purity": 0.9936781104574589,
|
||||
"f1": 0.9881253819959837,
|
||||
"rms_x_um": 1.2557356118085499,
|
||||
"rms_y_um": 1.2717035058014219,
|
||||
"rms_1d_um": 1.2637589164174359,
|
||||
"sigma68_1d_um": 0.6203093953244389,
|
||||
"bias_x_um": 0.0022295850593656115,
|
||||
"bias_y_um": -0.009725683011503684,
|
||||
"energy_bias_keV": -0.0005942877499556029,
|
||||
"energy_rms_keV": 0.07511853024698728,
|
||||
"energy_sigma68_keV": 0.07571983337402344,
|
||||
"subpixel_nonuniformity": 0.0
|
||||
},
|
||||
"cluster+eta": {
|
||||
"n_true": 11517,
|
||||
"n_pred": 8703,
|
||||
"n_match": 8694,
|
||||
"efficiency": 0.7548840843969784,
|
||||
"purity": 0.9989658738366081,
|
||||
"f1": 0.8599406528189911,
|
||||
"rms_x_um": 1.229084279121203,
|
||||
"rms_y_um": 1.536032603232305,
|
||||
"rms_1d_um": 1.391442339494398,
|
||||
"sigma68_1d_um": 1.0775229320144666,
|
||||
"bias_x_um": 0.013097150067134751,
|
||||
"bias_y_um": -0.052921709356355914,
|
||||
"energy_bias_keV": -0.0001451129443842377,
|
||||
"energy_rms_keV": 0.07458658542337013,
|
||||
"energy_sigma68_keV": 0.07571983337402344,
|
||||
"subpixel_nonuniformity": 0.0
|
||||
}
|
||||
},
|
||||
"2%": {
|
||||
"occupancy": 0.02,
|
||||
"n_clusters": {
|
||||
"1": 21348,
|
||||
"2": 3974,
|
||||
"3": 850
|
||||
},
|
||||
"grid": {
|
||||
"n_true": 22967,
|
||||
"n_pred": 22739,
|
||||
"n_match": 22706,
|
||||
"efficiency": 0.9886358688553142,
|
||||
"purity": 0.9985487488455956,
|
||||
"f1": 0.9935675841246226,
|
||||
"rms_x_um": 0.8840547685138826,
|
||||
"rms_y_um": 0.897443485929105,
|
||||
"rms_1d_um": 0.8908252397116158,
|
||||
"sigma68_1d_um": 0.6226322579383851,
|
||||
"bias_x_um": -0.014619298898143663,
|
||||
"bias_y_um": 0.00443699905276561,
|
||||
"energy_bias_keV": 0.0016991545489776674,
|
||||
"energy_rms_keV": 0.07503275623361767,
|
||||
"energy_sigma68_keV": 0.07495996570587157,
|
||||
"subpixel_nonuniformity": 0.0343833649100895
|
||||
},
|
||||
"cluster+dl": {
|
||||
"n_true": 22967,
|
||||
"n_pred": 21511,
|
||||
"n_match": 21081,
|
||||
"efficiency": 0.9178821787782471,
|
||||
"purity": 0.9800102273255543,
|
||||
"f1": 0.9479293133684068,
|
||||
"rms_x_um": 1.7980454666261474,
|
||||
"rms_y_um": 1.9693026447914417,
|
||||
"rms_1d_um": 1.8856215468354824,
|
||||
"sigma68_1d_um": 0.6749886225163936,
|
||||
"bias_x_um": 0.014511438090085866,
|
||||
"bias_y_um": 0.0087098963865713,
|
||||
"energy_bias_keV": -0.0004957638906067483,
|
||||
"energy_rms_keV": 0.07521611663195726,
|
||||
"energy_sigma68_keV": 0.07571983337402344,
|
||||
"subpixel_nonuniformity": 0.011337602563848385
|
||||
},
|
||||
"cluster+eta": {
|
||||
"n_true": 22967,
|
||||
"n_pred": 13504,
|
||||
"n_match": 13482,
|
||||
"efficiency": 0.5870161536117038,
|
||||
"purity": 0.9983708530805687,
|
||||
"f1": 0.7393271366291027,
|
||||
"rms_x_um": 1.2353796613534593,
|
||||
"rms_y_um": 1.4988550896341988,
|
||||
"rms_1d_um": 1.3736238983235192,
|
||||
"sigma68_1d_um": 1.0383780446953095,
|
||||
"bias_x_um": 0.006909224694715276,
|
||||
"bias_y_um": -0.03681126667657988,
|
||||
"energy_bias_keV": -0.0002414711574616126,
|
||||
"energy_rms_keV": 0.07536852939956286,
|
||||
"energy_sigma68_keV": 0.07571983337402344,
|
||||
"subpixel_nonuniformity": 0.0
|
||||
}
|
||||
},
|
||||
"5%": {
|
||||
"occupancy": 0.05,
|
||||
"n_clusters": {
|
||||
"1": 24379,
|
||||
"2": 7903,
|
||||
"3": 3054
|
||||
},
|
||||
"grid": {
|
||||
"n_true": 57515,
|
||||
"n_pred": 56257,
|
||||
"n_match": 56116,
|
||||
"efficiency": 0.9756759106320091,
|
||||
"purity": 0.9974936452352596,
|
||||
"f1": 0.9864641563829414,
|
||||
"rms_x_um": 1.1096336462326366,
|
||||
"rms_y_um": 1.1405961865081073,
|
||||
"rms_1d_um": 1.125226807707352,
|
||||
"sigma68_1d_um": 0.7069267165660855,
|
||||
"bias_x_um": -0.004130621426834062,
|
||||
"bias_y_um": 0.002833291005575017,
|
||||
"energy_bias_keV": 0.0018168478360816108,
|
||||
"energy_rms_keV": 0.0751094479278836,
|
||||
"energy_sigma68_keV": 0.07504721689224243,
|
||||
"subpixel_nonuniformity": 0.04489852797698968
|
||||
},
|
||||
"cluster+dl": {
|
||||
"n_true": 57515,
|
||||
"n_pred": 34642,
|
||||
"n_match": 32070,
|
||||
"efficiency": 0.5575936712162045,
|
||||
"purity": 0.9257548640378731,
|
||||
"f1": 0.6959861974673656,
|
||||
"rms_x_um": 3.4728496839199163,
|
||||
"rms_y_um": 3.5706318408598943,
|
||||
"rms_1d_um": 3.522469318121268,
|
||||
"sigma68_1d_um": 0.9264733225456439,
|
||||
"bias_x_um": 0.09430688218434768,
|
||||
"bias_y_um": -0.010416793708416822,
|
||||
"energy_bias_keV": -0.0007335710124059522,
|
||||
"energy_rms_keV": 0.07520841930408713,
|
||||
"energy_sigma68_keV": 0.07571983337402344,
|
||||
"subpixel_nonuniformity": 0.0
|
||||
},
|
||||
"cluster+eta": {
|
||||
"n_true": 57515,
|
||||
"n_pred": 15127,
|
||||
"n_match": 15108,
|
||||
"efficiency": 0.2626793010518995,
|
||||
"purity": 0.998743967739803,
|
||||
"f1": 0.41595771041546215,
|
||||
"rms_x_um": 1.5317970911426355,
|
||||
"rms_y_um": 1.6795084045360822,
|
||||
"rms_1d_um": 1.6077192482035705,
|
||||
"sigma68_1d_um": 1.0824790068734453,
|
||||
"bias_x_um": -0.013584749600640284,
|
||||
"bias_y_um": -0.08245495721077989,
|
||||
"energy_bias_keV": -0.0005271548406769114,
|
||||
"energy_rms_keV": 0.07594497954518455,
|
||||
"energy_sigma68_keV": 0.07631969451904297,
|
||||
"subpixel_nonuniformity": 0.0
|
||||
}
|
||||
},
|
||||
"10%": {
|
||||
"occupancy": 0.1,
|
||||
"n_clusters": {
|
||||
"1": 13316,
|
||||
"2": 5141,
|
||||
"3": 2348
|
||||
},
|
||||
"grid": {
|
||||
"n_true": 115143,
|
||||
"n_pred": 111060,
|
||||
"n_match": 110196,
|
||||
"efficiency": 0.9570360334540527,
|
||||
"purity": 0.9922204213938411,
|
||||
"f1": 0.9743106855346745,
|
||||
"rms_x_um": 1.7376297019554447,
|
||||
"rms_y_um": 1.7358375881557624,
|
||||
"rms_1d_um": 1.7367396954261378,
|
||||
"sigma68_1d_um": 0.9419664311408997,
|
||||
"bias_x_um": -0.0024142715432361847,
|
||||
"bias_y_um": 0.0065774764031168555,
|
||||
"energy_bias_keV": 0.002688690471001825,
|
||||
"energy_rms_keV": 0.07537169200633662,
|
||||
"energy_sigma68_keV": 0.0753557710647583,
|
||||
"subpixel_nonuniformity": 0.08680207623139889
|
||||
},
|
||||
"cluster+dl": {
|
||||
"n_true": 115143,
|
||||
"n_pred": 21623,
|
||||
"n_match": 18558,
|
||||
"efficiency": 0.16117349730335323,
|
||||
"purity": 0.858252786384868,
|
||||
"f1": 0.2713832385241946,
|
||||
"rms_x_um": 4.976208387415414,
|
||||
"rms_y_um": 5.1820745880493195,
|
||||
"rms_1d_um": 5.082711541224097,
|
||||
"sigma68_1d_um": 1.6431294292211531,
|
||||
"bias_x_um": 0.23931323555584702,
|
||||
"bias_y_um": -0.0812059417026731,
|
||||
"energy_bias_keV": -0.00028108258046445075,
|
||||
"energy_rms_keV": 0.075351238539105,
|
||||
"energy_sigma68_keV": 0.07571983337402344,
|
||||
"subpixel_nonuniformity": 0.04207391458993803
|
||||
},
|
||||
"cluster+eta": {
|
||||
"n_true": 115143,
|
||||
"n_pred": 8060,
|
||||
"n_match": 8050,
|
||||
"efficiency": 0.0699130646239893,
|
||||
"purity": 0.9987593052109182,
|
||||
"f1": 0.13067863607217356,
|
||||
"rms_x_um": 1.865479807388517,
|
||||
"rms_y_um": 2.127355542162366,
|
||||
"rms_1d_um": 2.000837040997611,
|
||||
"sigma68_1d_um": 1.2786324015140729,
|
||||
"bias_x_um": -0.015563024079104761,
|
||||
"bias_y_um": 0.030070619494817805,
|
||||
"energy_bias_keV": 0.000531021615733271,
|
||||
"energy_rms_keV": 0.07509626089279871,
|
||||
"energy_sigma68_keV": 0.07571983337402344,
|
||||
"subpixel_nonuniformity": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
experiment:
|
||||
name: 12keV_Moench040
|
||||
results_dir: Results
|
||||
data:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/GridBased/12keV_Moench040_150V
|
||||
train_shards:
|
||||
- 0
|
||||
- 11
|
||||
val_shards:
|
||||
- 0
|
||||
- 1
|
||||
max_train_frames: null
|
||||
max_val_frames: 8000
|
||||
input_scale: 12.0
|
||||
energy_scale: 12.0
|
||||
augment: true
|
||||
batch_size_train: 256
|
||||
batch_size_val: 512
|
||||
num_workers: 8
|
||||
model:
|
||||
channels:
|
||||
- 32
|
||||
- 64
|
||||
- 64
|
||||
- 64
|
||||
predict_energy: true
|
||||
norm: none
|
||||
prior_prob: 0.01
|
||||
loss:
|
||||
w_obj: 1.0
|
||||
w_off: 1.0
|
||||
w_ene: 0.1
|
||||
focal_alpha: 0.25
|
||||
focal_gamma: 2.0
|
||||
smooth_l1_beta_offset: 0.01
|
||||
smooth_l1_beta_energy: 0.02
|
||||
training:
|
||||
epochs: 200
|
||||
lr: 0.001
|
||||
weight_decay: 0.0
|
||||
scheduler_factor: 0.5
|
||||
scheduler_patience: 4
|
||||
amp: true
|
||||
seed: 0
|
||||
checkpoint_epochs:
|
||||
- 20
|
||||
- 40
|
||||
- 60
|
||||
- 80
|
||||
- 100
|
||||
- 200
|
||||
eval:
|
||||
threshold: 0.3
|
||||
merge_distance: 0.3
|
||||
match_radius: 1.0
|
||||
pixel_size_um: 25.0
|
||||
|
After Width: | Height: | Size: 136 KiB |
|
After Width: | Height: | Size: 133 KiB |
|
After Width: | Height: | Size: 262 KiB |
|
After Width: | Height: | Size: 67 KiB |
@@ -0,0 +1,436 @@
|
||||
{
|
||||
"0.5%": {
|
||||
"occupancy": 0.005,
|
||||
"n_clusters": {
|
||||
"1": 7967,
|
||||
"2": 447,
|
||||
"3": 26
|
||||
},
|
||||
"grid": {
|
||||
"n_true": 5827,
|
||||
"n_pred": 5810,
|
||||
"n_match": 5804,
|
||||
"efficiency": 0.9960528573880213,
|
||||
"purity": 0.9989672977624785,
|
||||
"f1": 0.9975079487840509,
|
||||
"rms_x_um": 0.7745434329391213,
|
||||
"rms_y_um": 0.8335377276606065,
|
||||
"rms_1d_um": 0.8045842853682927,
|
||||
"sigma68_1d_um": 0.5930900573730469,
|
||||
"bias_x_um": -0.001291214885751105,
|
||||
"bias_y_um": -0.005550693841246717,
|
||||
"energy_bias_keV": -0.0014806291631465941,
|
||||
"energy_rms_keV": 0.07487331357185813,
|
||||
"energy_sigma68_keV": 0.07521422080993652,
|
||||
"subpixel_nonuniformity": 0.05038651004579847
|
||||
},
|
||||
"cluster+dl": {
|
||||
"n_true": 5827,
|
||||
"n_pred": 5822,
|
||||
"n_match": 5806,
|
||||
"efficiency": 0.9963960871803672,
|
||||
"purity": 0.9972518035039505,
|
||||
"f1": 0.996823761696283,
|
||||
"rms_x_um": 0.8350069908627891,
|
||||
"rms_y_um": 0.9438987529996069,
|
||||
"rms_1d_um": 0.8911333851614491,
|
||||
"sigma68_1d_um": 0.5948124534264206,
|
||||
"bias_x_um": 0.009228541323870772,
|
||||
"bias_y_um": -0.001344026449815599,
|
||||
"energy_bias_keV": -0.0020763391960582937,
|
||||
"energy_rms_keV": 0.0751517504762937,
|
||||
"energy_sigma68_keV": 0.07571983337402344,
|
||||
"subpixel_nonuniformity": 0.03405747622316486
|
||||
},
|
||||
"cluster+eta": {
|
||||
"n_true": 5827,
|
||||
"n_pred": 5085,
|
||||
"n_match": 5078,
|
||||
"efficiency": 0.8714604427664321,
|
||||
"purity": 0.9986234021632252,
|
||||
"f1": 0.9307184750733137,
|
||||
"rms_x_um": 1.082732698577549,
|
||||
"rms_y_um": 1.707804172101413,
|
||||
"rms_1d_um": 1.4298435589774205,
|
||||
"sigma68_1d_um": 1.1606203316388393,
|
||||
"bias_x_um": -0.0503576774662195,
|
||||
"bias_y_um": -0.0505550725893291,
|
||||
"energy_bias_keV": -0.001967431617186923,
|
||||
"energy_rms_keV": 0.07507446519993481,
|
||||
"energy_sigma68_keV": 0.07571983337402344,
|
||||
"subpixel_nonuniformity": 0.0
|
||||
}
|
||||
},
|
||||
"1%": {
|
||||
"occupancy": 0.01,
|
||||
"n_clusters": {
|
||||
"1": 13719,
|
||||
"2": 1525,
|
||||
"3": 171
|
||||
},
|
||||
"grid": {
|
||||
"n_true": 11517,
|
||||
"n_pred": 11465,
|
||||
"n_match": 11452,
|
||||
"efficiency": 0.9943561691412695,
|
||||
"purity": 0.9988661142607937,
|
||||
"f1": 0.9966060395091811,
|
||||
"rms_x_um": 0.8661869603229555,
|
||||
"rms_y_um": 0.8529609720773376,
|
||||
"rms_1d_um": 0.8596026616510635,
|
||||
"sigma68_1d_um": 0.6102085113525391,
|
||||
"bias_x_um": -0.005408274182230703,
|
||||
"bias_y_um": -0.000675048105291166,
|
||||
"energy_bias_keV": -0.00018757687887444266,
|
||||
"energy_rms_keV": 0.07481183059546273,
|
||||
"energy_sigma68_keV": 0.07515103788375854,
|
||||
"subpixel_nonuniformity": 0.0
|
||||
},
|
||||
"cluster+dl": {
|
||||
"n_true": 11517,
|
||||
"n_pred": 11389,
|
||||
"n_match": 11317,
|
||||
"efficiency": 0.9826343665885213,
|
||||
"purity": 0.9936781104574589,
|
||||
"f1": 0.9881253819959837,
|
||||
"rms_x_um": 1.2557356118085499,
|
||||
"rms_y_um": 1.2717035058014219,
|
||||
"rms_1d_um": 1.2637589164174359,
|
||||
"sigma68_1d_um": 0.6203093953244389,
|
||||
"bias_x_um": 0.0022295850593656115,
|
||||
"bias_y_um": -0.009725683011503684,
|
||||
"energy_bias_keV": -0.0005942877499556029,
|
||||
"energy_rms_keV": 0.07511853024698728,
|
||||
"energy_sigma68_keV": 0.07571983337402344,
|
||||
"subpixel_nonuniformity": 0.0
|
||||
},
|
||||
"cluster+eta": {
|
||||
"n_true": 11517,
|
||||
"n_pred": 8703,
|
||||
"n_match": 8694,
|
||||
"efficiency": 0.7548840843969784,
|
||||
"purity": 0.9989658738366081,
|
||||
"f1": 0.8599406528189911,
|
||||
"rms_x_um": 1.229084279121203,
|
||||
"rms_y_um": 1.536032603232305,
|
||||
"rms_1d_um": 1.391442339494398,
|
||||
"sigma68_1d_um": 1.0775229320144666,
|
||||
"bias_x_um": 0.013097150067134751,
|
||||
"bias_y_um": -0.052921709356355914,
|
||||
"energy_bias_keV": -0.0001451129443842377,
|
||||
"energy_rms_keV": 0.07458658542337013,
|
||||
"energy_sigma68_keV": 0.07571983337402344,
|
||||
"subpixel_nonuniformity": 0.0
|
||||
}
|
||||
},
|
||||
"2%": {
|
||||
"occupancy": 0.02,
|
||||
"n_clusters": {
|
||||
"1": 21348,
|
||||
"2": 3974,
|
||||
"3": 850
|
||||
},
|
||||
"grid": {
|
||||
"n_true": 22967,
|
||||
"n_pred": 22786,
|
||||
"n_match": 22739,
|
||||
"efficiency": 0.990072713023033,
|
||||
"purity": 0.9979373299394365,
|
||||
"f1": 0.9939894651716827,
|
||||
"rms_x_um": 0.885974177465255,
|
||||
"rms_y_um": 0.9034271571451504,
|
||||
"rms_1d_um": 0.8947571981462589,
|
||||
"sigma68_1d_um": 0.6241321563720703,
|
||||
"bias_x_um": -0.007395124869504104,
|
||||
"bias_y_um": 0.002606461653006287,
|
||||
"energy_bias_keV": 3.3262636894401553e-06,
|
||||
"energy_rms_keV": 0.07501879666750082,
|
||||
"energy_sigma68_keV": 0.07489024848937986,
|
||||
"subpixel_nonuniformity": 0.029694204725319234
|
||||
},
|
||||
"cluster+dl": {
|
||||
"n_true": 22967,
|
||||
"n_pred": 21511,
|
||||
"n_match": 21081,
|
||||
"efficiency": 0.9178821787782471,
|
||||
"purity": 0.9800102273255543,
|
||||
"f1": 0.9479293133684068,
|
||||
"rms_x_um": 1.7980454666261474,
|
||||
"rms_y_um": 1.9693026447914417,
|
||||
"rms_1d_um": 1.8856215468354824,
|
||||
"sigma68_1d_um": 0.6749886225163936,
|
||||
"bias_x_um": 0.014511438090085866,
|
||||
"bias_y_um": 0.0087098963865713,
|
||||
"energy_bias_keV": -0.0004957638906067483,
|
||||
"energy_rms_keV": 0.07521611663195726,
|
||||
"energy_sigma68_keV": 0.07571983337402344,
|
||||
"subpixel_nonuniformity": 0.011337602563848385
|
||||
},
|
||||
"cluster+eta": {
|
||||
"n_true": 22967,
|
||||
"n_pred": 13504,
|
||||
"n_match": 13482,
|
||||
"efficiency": 0.5870161536117038,
|
||||
"purity": 0.9983708530805687,
|
||||
"f1": 0.7393271366291027,
|
||||
"rms_x_um": 1.2353796613534593,
|
||||
"rms_y_um": 1.4988550896341988,
|
||||
"rms_1d_um": 1.3736238983235192,
|
||||
"sigma68_1d_um": 1.0383780446953095,
|
||||
"bias_x_um": 0.006909224694715276,
|
||||
"bias_y_um": -0.03681126667657988,
|
||||
"energy_bias_keV": -0.0002414711574616126,
|
||||
"energy_rms_keV": 0.07536852939956286,
|
||||
"energy_sigma68_keV": 0.07571983337402344,
|
||||
"subpixel_nonuniformity": 0.0
|
||||
}
|
||||
},
|
||||
"5%": {
|
||||
"occupancy": 0.05,
|
||||
"n_clusters": {
|
||||
"1": 24379,
|
||||
"2": 7903,
|
||||
"3": 3054
|
||||
},
|
||||
"grid": {
|
||||
"n_true": 57515,
|
||||
"n_pred": 56675,
|
||||
"n_match": 56339,
|
||||
"efficiency": 0.9795531600452057,
|
||||
"purity": 0.9940714600794001,
|
||||
"f1": 0.9867589105876172,
|
||||
"rms_x_um": 1.1322819427596782,
|
||||
"rms_y_um": 1.1493623024279898,
|
||||
"rms_1d_um": 1.1408551638667521,
|
||||
"sigma68_1d_um": 0.7100862455368041,
|
||||
"bias_x_um": 0.005627413540319478,
|
||||
"bias_y_um": 0.0024938211393812516,
|
||||
"energy_bias_keV": -0.0001618699775754979,
|
||||
"energy_rms_keV": 0.07509903651258737,
|
||||
"energy_sigma68_keV": 0.0750441799163818,
|
||||
"subpixel_nonuniformity": 0.04059674469906677
|
||||
},
|
||||
"cluster+dl": {
|
||||
"n_true": 57515,
|
||||
"n_pred": 34642,
|
||||
"n_match": 32070,
|
||||
"efficiency": 0.5575936712162045,
|
||||
"purity": 0.9257548640378731,
|
||||
"f1": 0.6959861974673656,
|
||||
"rms_x_um": 3.4728496839199163,
|
||||
"rms_y_um": 3.5706318408598943,
|
||||
"rms_1d_um": 3.522469318121268,
|
||||
"sigma68_1d_um": 0.9264733225456439,
|
||||
"bias_x_um": 0.09430688218434768,
|
||||
"bias_y_um": -0.010416793708416822,
|
||||
"energy_bias_keV": -0.0007335710124059522,
|
||||
"energy_rms_keV": 0.07520841930408713,
|
||||
"energy_sigma68_keV": 0.07571983337402344,
|
||||
"subpixel_nonuniformity": 0.0
|
||||
},
|
||||
"cluster+eta": {
|
||||
"n_true": 57515,
|
||||
"n_pred": 15127,
|
||||
"n_match": 15108,
|
||||
"efficiency": 0.2626793010518995,
|
||||
"purity": 0.998743967739803,
|
||||
"f1": 0.41595771041546215,
|
||||
"rms_x_um": 1.5317970911426355,
|
||||
"rms_y_um": 1.6795084045360822,
|
||||
"rms_1d_um": 1.6077192482035705,
|
||||
"sigma68_1d_um": 1.0824790068734453,
|
||||
"bias_x_um": -0.013584749600640284,
|
||||
"bias_y_um": -0.08245495721077989,
|
||||
"energy_bias_keV": -0.0005271548406769114,
|
||||
"energy_rms_keV": 0.07594497954518455,
|
||||
"energy_sigma68_keV": 0.07631969451904297,
|
||||
"subpixel_nonuniformity": 0.0
|
||||
}
|
||||
},
|
||||
"10%": {
|
||||
"occupancy": 0.1,
|
||||
"n_clusters": {
|
||||
"1": 13316,
|
||||
"2": 5141,
|
||||
"3": 2348
|
||||
},
|
||||
"grid": {
|
||||
"n_true": 115143,
|
||||
"n_pred": 112894,
|
||||
"n_match": 110959,
|
||||
"efficiency": 0.9636625761010222,
|
||||
"purity": 0.9828600279908587,
|
||||
"f1": 0.9731666352390183,
|
||||
"rms_x_um": 1.7641263035880943,
|
||||
"rms_y_um": 1.7773972091960508,
|
||||
"rms_1d_um": 1.770774194091949,
|
||||
"sigma68_1d_um": 0.9449005126953125,
|
||||
"bias_x_um": 0.0020271530072638495,
|
||||
"bias_y_um": 0.0023051986111262317,
|
||||
"energy_bias_keV": 0.000466546579235357,
|
||||
"energy_rms_keV": 0.07535016847283477,
|
||||
"energy_sigma68_keV": 0.07532508831024169,
|
||||
"subpixel_nonuniformity": 0.06860082570918818
|
||||
},
|
||||
"cluster+dl": {
|
||||
"n_true": 115143,
|
||||
"n_pred": 21623,
|
||||
"n_match": 18558,
|
||||
"efficiency": 0.16117349730335323,
|
||||
"purity": 0.858252786384868,
|
||||
"f1": 0.2713832385241946,
|
||||
"rms_x_um": 4.976208387415414,
|
||||
"rms_y_um": 5.1820745880493195,
|
||||
"rms_1d_um": 5.082711541224097,
|
||||
"sigma68_1d_um": 1.6431294292211531,
|
||||
"bias_x_um": 0.23931323555584702,
|
||||
"bias_y_um": -0.0812059417026731,
|
||||
"energy_bias_keV": -0.00028108258046445075,
|
||||
"energy_rms_keV": 0.075351238539105,
|
||||
"energy_sigma68_keV": 0.07571983337402344,
|
||||
"subpixel_nonuniformity": 0.04207391458993803
|
||||
},
|
||||
"cluster+eta": {
|
||||
"n_true": 115143,
|
||||
"n_pred": 8060,
|
||||
"n_match": 8050,
|
||||
"efficiency": 0.0699130646239893,
|
||||
"purity": 0.9987593052109182,
|
||||
"f1": 0.13067863607217356,
|
||||
"rms_x_um": 1.865479807388517,
|
||||
"rms_y_um": 2.127355542162366,
|
||||
"rms_1d_um": 2.000837040997611,
|
||||
"sigma68_1d_um": 1.2786324015140729,
|
||||
"bias_x_um": -0.015563024079104761,
|
||||
"bias_y_um": 0.030070619494817805,
|
||||
"energy_bias_keV": 0.000531021615733271,
|
||||
"energy_rms_keV": 0.07509626089279871,
|
||||
"energy_sigma68_keV": 0.07571983337402344,
|
||||
"subpixel_nonuniformity": 0.0
|
||||
}
|
||||
},
|
||||
"20%": {
|
||||
"occupancy": 0.2,
|
||||
"n_clusters": {
|
||||
"1": 2255,
|
||||
"2": 567,
|
||||
"3": 206
|
||||
},
|
||||
"grid": {
|
||||
"n_true": 231173,
|
||||
"n_pred": 228056,
|
||||
"n_match": 216296,
|
||||
"efficiency": 0.9356455987507192,
|
||||
"purity": 0.9484337180341671,
|
||||
"f1": 0.9419962589470613,
|
||||
"rms_x_um": 3.3385438577531343,
|
||||
"rms_y_um": 3.341137638469033,
|
||||
"rms_1d_um": 3.3398790857128735,
|
||||
"sigma68_1d_um": 1.9790590143203723,
|
||||
"bias_x_um": 0.007890699622890065,
|
||||
"bias_y_um": -0.024009301283525575,
|
||||
"energy_bias_keV": 0.0008519556226341287,
|
||||
"energy_rms_keV": 0.07538286248419279,
|
||||
"energy_sigma68_keV": 0.0753316879272461,
|
||||
"subpixel_nonuniformity": 0.22801329767689676
|
||||
},
|
||||
"cluster+dl": {
|
||||
"n_true": 231173,
|
||||
"n_pred": 2673,
|
||||
"n_match": 2268,
|
||||
"efficiency": 0.009810834310235193,
|
||||
"purity": 0.8484848484848485,
|
||||
"f1": 0.01939738118248762,
|
||||
"rms_x_um": 5.600804109825136,
|
||||
"rms_y_um": 5.6995637998987,
|
||||
"rms_1d_um": 5.661411684798306,
|
||||
"sigma68_1d_um": 2.332519201468676,
|
||||
"bias_x_um": 0.34324095369484175,
|
||||
"bias_y_um": -0.3626348764505862,
|
||||
"energy_bias_keV": -0.002491474151611328,
|
||||
"energy_rms_keV": 0.07581166746186241,
|
||||
"energy_sigma68_keV": 0.07571983337402344,
|
||||
"subpixel_nonuniformity": 0.12366690732059063
|
||||
},
|
||||
"cluster+eta": {
|
||||
"n_true": 231173,
|
||||
"n_pred": 1314,
|
||||
"n_match": 1314,
|
||||
"efficiency": 0.005684054798787056,
|
||||
"purity": 1.0,
|
||||
"f1": 0.011303857850116351,
|
||||
"rms_x_um": 2.7328261611140303,
|
||||
"rms_y_um": 3.506679426249117,
|
||||
"rms_1d_um": 3.1479970134845514,
|
||||
"sigma68_1d_um": 2.194430853531226,
|
||||
"bias_x_um": 0.15264096415091147,
|
||||
"bias_y_um": -0.17790697024658175,
|
||||
"energy_bias_keV": -0.001253210790625446,
|
||||
"energy_rms_keV": 0.0767208912432988,
|
||||
"energy_sigma68_keV": 0.07631969451904297,
|
||||
"subpixel_nonuniformity": 0.0
|
||||
}
|
||||
},
|
||||
"50%": {
|
||||
"occupancy": 0.5,
|
||||
"n_clusters": {
|
||||
"1": 10,
|
||||
"2": 0,
|
||||
"3": 0
|
||||
},
|
||||
"grid": {
|
||||
"n_true": 575839,
|
||||
"n_pred": 555660,
|
||||
"n_match": 499668,
|
||||
"efficiency": 0.8677217069354455,
|
||||
"purity": 0.8992333441313033,
|
||||
"f1": 0.8831965383972941,
|
||||
"rms_x_um": 6.495733528908615,
|
||||
"rms_y_um": 6.442457447026989,
|
||||
"rms_1d_um": 6.469658583455593,
|
||||
"sigma68_1d_um": 6.024599075317383,
|
||||
"bias_x_um": 0.03891640526856525,
|
||||
"bias_y_um": -0.12327075587659811,
|
||||
"energy_bias_keV": 0.00048489472400298797,
|
||||
"energy_rms_keV": 0.0754558084371303,
|
||||
"energy_sigma68_keV": 0.07545852661132812,
|
||||
"subpixel_nonuniformity": 0.8956750975587188
|
||||
},
|
||||
"cluster+dl": {
|
||||
"n_true": 575839,
|
||||
"n_pred": 4,
|
||||
"n_match": 4,
|
||||
"efficiency": 6.9463860558246315e-06,
|
||||
"purity": 1.0,
|
||||
"f1": 1.3892675607761142e-05,
|
||||
"rms_x_um": 3.06150730399529,
|
||||
"rms_y_um": 1.149143139756944,
|
||||
"rms_1d_um": 2.326963994002116,
|
||||
"sigma68_1d_um": 1.6002655395772307,
|
||||
"bias_x_um": 0.2986684557981789,
|
||||
"bias_y_um": -0.22318579722195864,
|
||||
"energy_bias_keV": 0.05219006538391113,
|
||||
"energy_rms_keV": 0.05516777821186253,
|
||||
"energy_sigma68_keV": 0.10123404273986816,
|
||||
"subpixel_nonuniformity": 3.391164991562633
|
||||
},
|
||||
"cluster+eta": {
|
||||
"n_true": 575839,
|
||||
"n_pred": 4,
|
||||
"n_match": 4,
|
||||
"efficiency": 6.9463860558246315e-06,
|
||||
"purity": 1.0,
|
||||
"f1": 1.3892675607761142e-05,
|
||||
"rms_x_um": 8.111969195945287,
|
||||
"rms_y_um": 6.438365439935207,
|
||||
"rms_1d_um": 7.81500657487365,
|
||||
"sigma68_1d_um": 8.139267043592614,
|
||||
"bias_x_um": -4.3387687281502165,
|
||||
"bias_y_um": 1.1187145300044943,
|
||||
"energy_bias_keV": 0.05219006538391113,
|
||||
"energy_rms_keV": 0.05516777821186253,
|
||||
"energy_sigma68_keV": 0.10123404273986816,
|
||||
"subpixel_nonuniformity": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
experiment:
|
||||
name: 12keV_Moench040
|
||||
results_dir: Results
|
||||
data:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/GridBased/12keV_Moench040_150V
|
||||
train_shards:
|
||||
- 0
|
||||
- 11
|
||||
val_shards:
|
||||
- 0
|
||||
- 1
|
||||
max_train_frames: null
|
||||
max_val_frames: 8000
|
||||
input_scale: 12.0
|
||||
energy_scale: 12.0
|
||||
augment: true
|
||||
batch_size_train: 256
|
||||
batch_size_val: 512
|
||||
num_workers: 8
|
||||
model:
|
||||
channels:
|
||||
- 32
|
||||
- 64
|
||||
- 64
|
||||
- 64
|
||||
predict_energy: true
|
||||
norm: none
|
||||
prior_prob: 0.01
|
||||
loss:
|
||||
w_obj: 1.0
|
||||
w_off: 1.0
|
||||
w_ene: 0.1
|
||||
focal_alpha: 0.25
|
||||
focal_gamma: 2.0
|
||||
smooth_l1_beta_offset: 0.01
|
||||
smooth_l1_beta_energy: 0.02
|
||||
training:
|
||||
epochs: 150
|
||||
lr: 0.001
|
||||
weight_decay: 0.0
|
||||
scheduler_factor: 0.5
|
||||
scheduler_patience: 4
|
||||
amp: true
|
||||
seed: 0
|
||||
checkpoint_epochs:
|
||||
- 25
|
||||
- 50
|
||||
- 75
|
||||
- 100
|
||||
- 125
|
||||
- 150
|
||||
eval:
|
||||
threshold: 0.3
|
||||
merge_distance: 0.1
|
||||
match_radius: 1.0
|
||||
pixel_size_um: 25.0
|
||||
@@ -0,0 +1,914 @@
|
||||
{
|
||||
"train_loss": [
|
||||
0.11549803302764892,
|
||||
0.08318714067379633,
|
||||
0.07850522745132446,
|
||||
0.07633025724887849,
|
||||
0.07498112595160802,
|
||||
0.07409019044558207,
|
||||
0.073438043709596,
|
||||
0.07298669574975968,
|
||||
0.07263013871828715,
|
||||
0.07234264065146447,
|
||||
0.07211381237904231,
|
||||
0.07190426727851232,
|
||||
0.07173082770824432,
|
||||
0.07156399731993675,
|
||||
0.07143148451566696,
|
||||
0.07131937425533931,
|
||||
0.07119757150053978,
|
||||
0.0711051474304994,
|
||||
0.07102341193238894,
|
||||
0.07093638002713522,
|
||||
0.07087182137012482,
|
||||
0.0707879904782772,
|
||||
0.0707431219124794,
|
||||
0.07067672574718793,
|
||||
0.07061363537311555,
|
||||
0.07056085242668787,
|
||||
0.07051102187474569,
|
||||
0.07045817246754964,
|
||||
0.07042840806245804,
|
||||
0.07037664879163107,
|
||||
0.07033685771465302,
|
||||
0.07029899738510449,
|
||||
0.07026120421051979,
|
||||
0.07021202997763952,
|
||||
0.07018921863516171,
|
||||
0.07015228042960167,
|
||||
0.07012904616991679,
|
||||
0.06943530514121056,
|
||||
0.06937986017425855,
|
||||
0.06935595335682233,
|
||||
0.0693249940419197,
|
||||
0.0693047307741642,
|
||||
0.0692897141079108,
|
||||
0.06925967580596606,
|
||||
0.06925501446247101,
|
||||
0.0692465750904878,
|
||||
0.06923532518029213,
|
||||
0.06921389070312182,
|
||||
0.06920927806854248,
|
||||
0.0691958756562074,
|
||||
0.06881222748597463,
|
||||
0.06879483518679937,
|
||||
0.0687770151857535,
|
||||
0.06876321306665738,
|
||||
0.06876243152062098,
|
||||
0.0687486151723067,
|
||||
0.0687376529943943,
|
||||
0.06874020044883092,
|
||||
0.068733786555926,
|
||||
0.06872081969221433,
|
||||
0.06870851689457894,
|
||||
0.06871340822935104,
|
||||
0.0684949930759271,
|
||||
0.06849531310518582,
|
||||
0.06847809389829636,
|
||||
0.06847691614627838,
|
||||
0.06847435382127762,
|
||||
0.0684768702741464,
|
||||
0.0684674886683623,
|
||||
0.06846663992245992,
|
||||
0.06845621688842773,
|
||||
0.06844923645218214,
|
||||
0.06845370108524958,
|
||||
0.0684496110912164,
|
||||
0.06843825560331344,
|
||||
0.0684471672519048,
|
||||
0.0683291863032182,
|
||||
0.06831207599600156,
|
||||
0.0683146153430144,
|
||||
0.06831508771657943,
|
||||
0.06831361457149188,
|
||||
0.06830971352418264,
|
||||
0.068305537712574,
|
||||
0.06830678311626116,
|
||||
0.06830184397061666,
|
||||
0.06825398347139358,
|
||||
0.06824112318714459,
|
||||
0.0682399377099673,
|
||||
0.06823793432633082,
|
||||
0.06823979368209838,
|
||||
0.0682375610311826,
|
||||
0.06823894005179405,
|
||||
0.06823871238708495,
|
||||
0.06823483720302581,
|
||||
0.06823230539282163,
|
||||
0.06823040001312891,
|
||||
0.06823249892552694,
|
||||
0.06823164344350496,
|
||||
0.06822990950345993,
|
||||
0.06822754492282868,
|
||||
0.06822746344765028,
|
||||
0.06821993305365244,
|
||||
0.06822170446475347,
|
||||
0.0682206405377388,
|
||||
0.0682171655523777,
|
||||
0.06818979968905449,
|
||||
0.06819452638745307,
|
||||
0.06818412415504456,
|
||||
0.06819036424557368,
|
||||
0.06819010560194651,
|
||||
0.06818557546933492,
|
||||
0.06818316753983497,
|
||||
0.06816729074835777,
|
||||
0.06817552491823832,
|
||||
0.06817265658418338,
|
||||
0.06817131195624669,
|
||||
0.06816850638389588,
|
||||
0.06816655315597853,
|
||||
0.06816250649571419,
|
||||
0.06815451193173726,
|
||||
0.06816244826118151,
|
||||
0.06816369408448537,
|
||||
0.06816202482104301,
|
||||
0.06816153821428617,
|
||||
0.06815770435969035,
|
||||
0.06815292869488399,
|
||||
0.0681535164296627,
|
||||
0.06814899826804798,
|
||||
0.06816054877201716,
|
||||
0.06815148009300231,
|
||||
0.06815126408775647,
|
||||
0.06815599991202355,
|
||||
0.06815279254118602,
|
||||
0.06815057228724161,
|
||||
0.06814749926010767,
|
||||
0.06815252566814423,
|
||||
0.06815187471707662,
|
||||
0.06815179258743922,
|
||||
0.0681491514325142,
|
||||
0.06815271788438161,
|
||||
0.06814763328433036,
|
||||
0.06814989734133084,
|
||||
0.0681492163904508,
|
||||
0.06816013643821081,
|
||||
0.0681472523287932,
|
||||
0.06814959580858548,
|
||||
0.06814836641192436,
|
||||
0.06814832310160002,
|
||||
0.06815474447727203,
|
||||
0.0681435151231289
|
||||
],
|
||||
"val_loss": [
|
||||
0.08761753863096237,
|
||||
0.08118068277835847,
|
||||
0.07696007710695267,
|
||||
0.07577203887701034,
|
||||
0.07487226217985153,
|
||||
0.07417588114738465,
|
||||
0.07336923974752427,
|
||||
0.07277206259965896,
|
||||
0.07290583366155624,
|
||||
0.07238588005304336,
|
||||
0.07192310702800751,
|
||||
0.07196190804243088,
|
||||
0.07193700063228607,
|
||||
0.07154968839883805,
|
||||
0.07180907106399537,
|
||||
0.07135853445529938,
|
||||
0.07156657356023788,
|
||||
0.07113019919395447,
|
||||
0.07104292362928391,
|
||||
0.0710218738913536,
|
||||
0.07134625041484832,
|
||||
0.07105319321155548,
|
||||
0.0710515564084053,
|
||||
0.07085513561964035,
|
||||
0.07069623172283172,
|
||||
0.07083315581083298,
|
||||
0.0707534500360489,
|
||||
0.07064944076538086,
|
||||
0.07058667445182801,
|
||||
0.07049528861045837,
|
||||
0.07071359670162201,
|
||||
0.0702024462223053,
|
||||
0.070397798538208,
|
||||
0.0705282074213028,
|
||||
0.07057095313072205,
|
||||
0.07052047687768936,
|
||||
0.0708088281750679,
|
||||
0.06966710406541825,
|
||||
0.069708351790905,
|
||||
0.06975338733196258,
|
||||
0.06956660330295562,
|
||||
0.06984174424409867,
|
||||
0.06944911295175553,
|
||||
0.06961576420068741,
|
||||
0.06933906447887421,
|
||||
0.06956946402788163,
|
||||
0.06945883828401565,
|
||||
0.06948346525430679,
|
||||
0.06955201673507691,
|
||||
0.06945740842819213,
|
||||
0.06912153285741807,
|
||||
0.06900744903087616,
|
||||
0.06909787338972091,
|
||||
0.06909513080120086,
|
||||
0.06915528351068496,
|
||||
0.06901137292385101,
|
||||
0.06893064504861832,
|
||||
0.06902213388681412,
|
||||
0.0690176460146904,
|
||||
0.06905519688129425,
|
||||
0.06893697673082352,
|
||||
0.06903553849458695,
|
||||
0.06877595669031143,
|
||||
0.06876467853784561,
|
||||
0.06878680843114852,
|
||||
0.06872492188215255,
|
||||
0.06882990360260009,
|
||||
0.06871770906448364,
|
||||
0.0687373777627945,
|
||||
0.06877333170175552,
|
||||
0.06867993527650833,
|
||||
0.06869136583805084,
|
||||
0.06870175909996033,
|
||||
0.06872516995668411,
|
||||
0.0686790629029274,
|
||||
0.06882987052202225,
|
||||
0.06860003381967544,
|
||||
0.06863409441709518,
|
||||
0.06863678550720215,
|
||||
0.06858499819040298,
|
||||
0.0686147688627243,
|
||||
0.06860790497064591,
|
||||
0.06860097223520278,
|
||||
0.06860156106948853,
|
||||
0.06866604322195054,
|
||||
0.06857422769069671,
|
||||
0.068542486846447,
|
||||
0.0685451517701149,
|
||||
0.06852209347486496,
|
||||
0.06857949012517929,
|
||||
0.06853350526094437,
|
||||
0.06852165567874909,
|
||||
0.06850533437728881,
|
||||
0.06854811006784439,
|
||||
0.0685215277671814,
|
||||
0.06851877021789551,
|
||||
0.06849726730585098,
|
||||
0.06852265816926956,
|
||||
0.06855925232172012,
|
||||
0.06849010229110718,
|
||||
0.06854420799016953,
|
||||
0.06848812222480774,
|
||||
0.06852071714401245,
|
||||
0.06853020858764648,
|
||||
0.06851188629865647,
|
||||
0.06849872785806656,
|
||||
0.06847186905145645,
|
||||
0.0684665448665619,
|
||||
0.06849229705333709,
|
||||
0.06848304557800293,
|
||||
0.0684949095249176,
|
||||
0.06847141987085342,
|
||||
0.0684635078907013,
|
||||
0.06846057045459747,
|
||||
0.06846488583087922,
|
||||
0.06845710617303848,
|
||||
0.06846144515275955,
|
||||
0.06846437907218933,
|
||||
0.06844912987947464,
|
||||
0.06844370687007904,
|
||||
0.06845692706108093,
|
||||
0.06845452892780304,
|
||||
0.06844369173049927,
|
||||
0.06844812226295471,
|
||||
0.06844230926036834,
|
||||
0.06844818329811096,
|
||||
0.06844752019643784,
|
||||
0.06844786524772645,
|
||||
0.06844825381040573,
|
||||
0.0684421449303627,
|
||||
0.06844730162620545,
|
||||
0.06844427931308747,
|
||||
0.06844561773538589,
|
||||
0.06844404506683349,
|
||||
0.06844152700901031,
|
||||
0.06844258272647857,
|
||||
0.06844352567195892,
|
||||
0.06844338977336883,
|
||||
0.06844412106275559,
|
||||
0.06844491696357727,
|
||||
0.06844289910793304,
|
||||
0.0684460974931717,
|
||||
0.06844513207674026,
|
||||
0.068443852186203,
|
||||
0.06844429087638855,
|
||||
0.06844322699308396,
|
||||
0.06844419091939927,
|
||||
0.06844343626499176,
|
||||
0.06844278138875962,
|
||||
0.06844274979829788
|
||||
],
|
||||
"efficiency": [
|
||||
0.9808896946991243,
|
||||
0.978973508511132,
|
||||
0.9799960473289395,
|
||||
0.9772721414025108,
|
||||
0.9798070065390928,
|
||||
0.9791023999587547,
|
||||
0.9795062598279729,
|
||||
0.9785524631155641,
|
||||
0.9802108664083109,
|
||||
0.9786899473263617,
|
||||
0.9795320381174975,
|
||||
0.978732911142236,
|
||||
0.979265662459077,
|
||||
0.9792570696959021,
|
||||
0.9787844677212851,
|
||||
0.9795664091701969,
|
||||
0.9784321644311161,
|
||||
0.9785266848260396,
|
||||
0.9789047664057331,
|
||||
0.9788360243003342,
|
||||
0.9790766216692302,
|
||||
0.9789477302216074,
|
||||
0.9790594361428805,
|
||||
0.9790594361428805,
|
||||
0.9793601828540004,
|
||||
0.9789219519320828,
|
||||
0.9783892006152418,
|
||||
0.9788961736425582,
|
||||
0.9797554499600436,
|
||||
0.9793945539066998,
|
||||
0.9789992868006565,
|
||||
0.9784579427206407,
|
||||
0.9786641690368372,
|
||||
0.9773838473237839,
|
||||
0.9781571960095208,
|
||||
0.9789477302216074,
|
||||
0.9782517164044442,
|
||||
0.9786641690368372,
|
||||
0.9798327848286174,
|
||||
0.9791625493009787,
|
||||
0.9790336578533559,
|
||||
0.9790938071955799,
|
||||
0.9779939335091985,
|
||||
0.9786727618000121,
|
||||
0.9791367710114541,
|
||||
0.9786212052209629,
|
||||
0.9792914407486015,
|
||||
0.9788188387739846,
|
||||
0.9777361506139529,
|
||||
0.978380607852067,
|
||||
0.9791195854851045,
|
||||
0.9790164723270062,
|
||||
0.9794117394330495,
|
||||
0.9787586894317606,
|
||||
0.9785868341682635,
|
||||
0.9789219519320828,
|
||||
0.9781571960095208,
|
||||
0.9787071328527115,
|
||||
0.9795406308806723,
|
||||
0.9785094992996898,
|
||||
0.9788188387739846,
|
||||
0.9780368973250728,
|
||||
0.9789391374584325,
|
||||
0.9789305446952576,
|
||||
0.9788188387739846,
|
||||
0.9786727618000121,
|
||||
0.9792742552222519,
|
||||
0.9785009065365149,
|
||||
0.9787844677212851,
|
||||
0.9791539565378039,
|
||||
0.978853209826684,
|
||||
0.9784751282469903,
|
||||
0.9788188387739846,
|
||||
0.9788188387739846,
|
||||
0.9786813545631868,
|
||||
0.9789219519320828,
|
||||
0.9786985400895366,
|
||||
0.9790766216692302,
|
||||
0.9788274315371595,
|
||||
0.9789477302216074,
|
||||
0.978913359168908,
|
||||
0.9789992868006565,
|
||||
0.9789821012743067,
|
||||
0.9788961736425582,
|
||||
0.9790164723270062,
|
||||
0.9788875808793834,
|
||||
0.9787500966685857,
|
||||
0.9788446170635091,
|
||||
0.9788875808793834,
|
||||
0.9790336578533559,
|
||||
0.9790594361428805,
|
||||
0.9789047664057331,
|
||||
0.9788875808793834,
|
||||
0.9789305446952576,
|
||||
0.9789047664057331,
|
||||
0.9788703953530337,
|
||||
0.9785610558787389,
|
||||
0.9788618025898588,
|
||||
0.9790250650901811,
|
||||
0.9789305446952576,
|
||||
0.9790164723270062,
|
||||
0.9789563229847822,
|
||||
0.9788446170635091,
|
||||
0.9791195854851045,
|
||||
0.9789391374584325,
|
||||
0.9787844677212851,
|
||||
0.9789047664057331,
|
||||
0.9789305446952576,
|
||||
0.9789047664057331,
|
||||
0.9788875808793834,
|
||||
0.9791539565378039,
|
||||
0.9789219519320828,
|
||||
0.978973508511132,
|
||||
0.9789305446952576,
|
||||
0.9789477302216074,
|
||||
0.9788961736425582,
|
||||
0.9788188387739846,
|
||||
0.9789391374584325,
|
||||
0.9788961736425582,
|
||||
0.9788789881162085,
|
||||
0.9788961736425582,
|
||||
0.979085214432405,
|
||||
0.978853209826684,
|
||||
0.978973508511132,
|
||||
0.9789649157479571,
|
||||
0.9789992868006565,
|
||||
0.9789906940374816,
|
||||
0.9789477302216074,
|
||||
0.9789992868006565,
|
||||
0.9789563229847822,
|
||||
0.9789563229847822,
|
||||
0.9788961736425582,
|
||||
0.9790078795638314,
|
||||
0.9789821012743067,
|
||||
0.9789305446952576,
|
||||
0.9789906940374816,
|
||||
0.9789906940374816,
|
||||
0.9789821012743067,
|
||||
0.9790078795638314,
|
||||
0.978973508511132,
|
||||
0.9789992868006565,
|
||||
0.9790078795638314,
|
||||
0.9789992868006565,
|
||||
0.9790078795638314,
|
||||
0.9789821012743067,
|
||||
0.9789821012743067,
|
||||
0.978973508511132,
|
||||
0.9789821012743067,
|
||||
0.9790078795638314,
|
||||
0.9789391374584325
|
||||
],
|
||||
"purity": [
|
||||
0.9767853781253744,
|
||||
0.9848635471685065,
|
||||
0.9858666712769268,
|
||||
0.9899811112174995,
|
||||
0.9889506595779741,
|
||||
0.9893291888794346,
|
||||
0.9902101303868172,
|
||||
0.990459044338917,
|
||||
0.9896157749997831,
|
||||
0.9909946751122403,
|
||||
0.9898234737381368,
|
||||
0.9906589201224604,
|
||||
0.9909913043478261,
|
||||
0.9911636037885179,
|
||||
0.9914526938811037,
|
||||
0.9905462823776795,
|
||||
0.9915187084751962,
|
||||
0.9918304069119287,
|
||||
0.991100091348036,
|
||||
0.9912115833072291,
|
||||
0.9909378696166423,
|
||||
0.9911091005576386,
|
||||
0.991041141167261,
|
||||
0.9911963254227851,
|
||||
0.991043867657928,
|
||||
0.9912295966310514,
|
||||
0.9924863149820439,
|
||||
0.9916348949356731,
|
||||
0.9912628449220177,
|
||||
0.991613234385739,
|
||||
0.9912647798359101,
|
||||
0.9918816745352869,
|
||||
0.9920043201059123,
|
||||
0.9924613250268304,
|
||||
0.9927961556239698,
|
||||
0.9917043871866296,
|
||||
0.9923382000435825,
|
||||
0.992704674412321,
|
||||
0.9914703810939823,
|
||||
0.9925094937811378,
|
||||
0.9923442725752508,
|
||||
0.9923620243683646,
|
||||
0.9926217927473793,
|
||||
0.9920475925022646,
|
||||
0.9927254669640369,
|
||||
0.9924967320261437,
|
||||
0.9925882701318609,
|
||||
0.992368540265533,
|
||||
0.9930616768923295,
|
||||
0.9924516460815676,
|
||||
0.9925523945575861,
|
||||
0.9926034987454697,
|
||||
0.9920708143299795,
|
||||
0.9923075582813534,
|
||||
0.9930590071589889,
|
||||
0.9925768453335192,
|
||||
0.9929866799256798,
|
||||
0.9926703852187555,
|
||||
0.9920027846669277,
|
||||
0.9930671224633952,
|
||||
0.9928182959140984,
|
||||
0.9932631138027628,
|
||||
0.9925683269587642,
|
||||
0.992697994998388,
|
||||
0.9926539148620975,
|
||||
0.9925749692802426,
|
||||
0.9923720622425789,
|
||||
0.9931623335281138,
|
||||
0.9927055645126149,
|
||||
0.9925007838901857,
|
||||
0.9927925886546456,
|
||||
0.9930668806195331,
|
||||
0.992541474975603,
|
||||
0.9927750324644199,
|
||||
0.9928519125492521,
|
||||
0.9928276991991076,
|
||||
0.9930338195419235,
|
||||
0.9928720808644127,
|
||||
0.9929222052734801,
|
||||
0.9928624962961672,
|
||||
0.9927065179505054,
|
||||
0.9928196101327152,
|
||||
0.9925513564371962,
|
||||
0.9928275116781705,
|
||||
0.9928024328822509,
|
||||
0.9927582330437208,
|
||||
0.9929822420211143,
|
||||
0.9928877112550226,
|
||||
0.9929399459600802,
|
||||
0.9927852568291726,
|
||||
0.9926297632115415,
|
||||
0.9929314146758126,
|
||||
0.9928620608511491,
|
||||
0.9927585485726237,
|
||||
0.9929054525170827,
|
||||
0.992740804001708,
|
||||
0.9931367675657763,
|
||||
0.9929830372552779,
|
||||
0.9928111466438947,
|
||||
0.9928623718887262,
|
||||
0.9928976034858388,
|
||||
0.9929923648153959,
|
||||
0.9930175389657938,
|
||||
0.9927339890748469,
|
||||
0.9926461618889953,
|
||||
0.9930344268440461,
|
||||
0.9930266208748104,
|
||||
0.9928018056487525,
|
||||
0.9929141064191398,
|
||||
0.9930005317155235,
|
||||
0.9926823531461526,
|
||||
0.9928796158304355,
|
||||
0.9928713354481123,
|
||||
0.9929575623403903,
|
||||
0.9929230688780624,
|
||||
0.9929400074957945,
|
||||
0.9929740755591974,
|
||||
0.9929316611032186,
|
||||
0.9929573168074332,
|
||||
0.9929398844232932,
|
||||
0.9929313530662762,
|
||||
0.9928115851108323,
|
||||
0.9930089436705661,
|
||||
0.9929405612689559,
|
||||
0.993061669208978,
|
||||
0.9929493995224068,
|
||||
0.9928887649457943,
|
||||
0.9930182692978174,
|
||||
0.9929320923098376,
|
||||
0.9929664008367107,
|
||||
0.9929144769524407,
|
||||
0.9929746267225675,
|
||||
0.9928802363378096,
|
||||
0.992931969113315,
|
||||
0.9929748716563092,
|
||||
0.992949338074446,
|
||||
0.9929839546092368,
|
||||
0.9929925480454962,
|
||||
0.9929927312660147,
|
||||
0.9930097967437158,
|
||||
0.9929840157576392,
|
||||
0.9929927312660147,
|
||||
0.9929753614725595,
|
||||
0.9930013857779095,
|
||||
0.9929579306077271,
|
||||
0.9929925480454962,
|
||||
0.9930097967437158,
|
||||
0.9929406227939446,
|
||||
0.9929754226947882,
|
||||
0.9930268640064153
|
||||
],
|
||||
"rms_1d_um": [
|
||||
1.6518027539794375,
|
||||
1.504959609515673,
|
||||
1.4434803632079867,
|
||||
1.3929337206509127,
|
||||
1.3889829255642838,
|
||||
1.3557948642462418,
|
||||
1.3534493343880807,
|
||||
1.3346827936556243,
|
||||
1.3387511021931806,
|
||||
1.3282341367673838,
|
||||
1.3240096560183134,
|
||||
1.3164025842707385,
|
||||
1.318616826569897,
|
||||
1.3113489967760021,
|
||||
1.3067453177081807,
|
||||
1.3106004290897346,
|
||||
1.3053162108734278,
|
||||
1.3068550316130951,
|
||||
1.2936912652797414,
|
||||
1.2848354424110855,
|
||||
1.3025805903766177,
|
||||
1.2744657305349245,
|
||||
1.3018190673573597,
|
||||
1.294878492660909,
|
||||
1.2812935040052742,
|
||||
1.2920731451099592,
|
||||
1.2794158917434293,
|
||||
1.2811052546058228,
|
||||
1.2855345245588357,
|
||||
1.2677654344424227,
|
||||
1.2737460890980223,
|
||||
1.2745940317386353,
|
||||
1.2728228024034562,
|
||||
1.2715848796325957,
|
||||
1.2686894108221383,
|
||||
1.2660857999864843,
|
||||
1.2659234569562197,
|
||||
1.251547579215351,
|
||||
1.259892240596265,
|
||||
1.2569207474628257,
|
||||
1.2525772739138858,
|
||||
1.2547406284918396,
|
||||
1.2425543367640481,
|
||||
1.259691377609029,
|
||||
1.2519940137486916,
|
||||
1.2541406468640504,
|
||||
1.245735781709769,
|
||||
1.2441952674493566,
|
||||
1.2440942301785545,
|
||||
1.2414551609062303,
|
||||
1.239263904030335,
|
||||
1.243810650881112,
|
||||
1.2434232102302194,
|
||||
1.2434599058044593,
|
||||
1.2461881799810886,
|
||||
1.239423895305759,
|
||||
1.2373037167896699,
|
||||
1.2391955861445278,
|
||||
1.2425751971858434,
|
||||
1.2374395687648991,
|
||||
1.245147558787495,
|
||||
1.2354060878053612,
|
||||
1.2367463431263799,
|
||||
1.2360888364221885,
|
||||
1.2373770863473879,
|
||||
1.237143623457706,
|
||||
1.2379887913482324,
|
||||
1.236886581386335,
|
||||
1.2322798196198916,
|
||||
1.2367419977305765,
|
||||
1.2321263416877766,
|
||||
1.230330805082824,
|
||||
1.2326743802255173,
|
||||
1.240304856444659,
|
||||
1.2337514924833444,
|
||||
1.239528013935537,
|
||||
1.2323571298499751,
|
||||
1.235188832440222,
|
||||
1.231610584019876,
|
||||
1.2342383179998853,
|
||||
1.2348576601443781,
|
||||
1.2342280448211749,
|
||||
1.2350061169415218,
|
||||
1.2361027848729111,
|
||||
1.2310652218690377,
|
||||
1.234599808073783,
|
||||
1.2354957264509132,
|
||||
1.233094696098922,
|
||||
1.2338188563582193,
|
||||
1.2332609355616289,
|
||||
1.2352743617679904,
|
||||
1.2338121086497793,
|
||||
1.2349447901528963,
|
||||
1.2341980109114,
|
||||
1.2345296910562715,
|
||||
1.2333577056292377,
|
||||
1.232961511544981,
|
||||
1.2330551226476572,
|
||||
1.2361446024400964,
|
||||
1.2344230878078382,
|
||||
1.2346198049168138,
|
||||
1.2349447709373782,
|
||||
1.2309930949828072,
|
||||
1.235229165826261,
|
||||
1.231999449482239,
|
||||
1.2326119172175054,
|
||||
1.2319315570409963,
|
||||
1.2325102103486516,
|
||||
1.2309485656691728,
|
||||
1.234818785346898,
|
||||
1.2306357129830934,
|
||||
1.2342077209574014,
|
||||
1.229782963262012,
|
||||
1.2328603977826504,
|
||||
1.2325025013776514,
|
||||
1.2328272993508755,
|
||||
1.2320834300155519,
|
||||
1.2312744992942681,
|
||||
1.2330552895207854,
|
||||
1.2321872107895615,
|
||||
1.2328192804492104,
|
||||
1.2344017833153023,
|
||||
1.2344088713033987,
|
||||
1.2317319130876823,
|
||||
1.2328836229477833,
|
||||
1.2312717539408862,
|
||||
1.2319299202289258,
|
||||
1.2326362497512104,
|
||||
1.2335916472439719,
|
||||
1.2329094812195518,
|
||||
1.2316179173291961,
|
||||
1.232136345858377,
|
||||
1.2325858042751041,
|
||||
1.2326276038654307,
|
||||
1.2336751824462562,
|
||||
1.233972178868589,
|
||||
1.2338528085537162,
|
||||
1.2330993942821638,
|
||||
1.2331512283836805,
|
||||
1.2337571690829185,
|
||||
1.233387926457071,
|
||||
1.233457575569663,
|
||||
1.2331978766845648,
|
||||
1.2332512704502663,
|
||||
1.233935626328691,
|
||||
1.233122942728529,
|
||||
1.233181678209779,
|
||||
1.233262819987371,
|
||||
1.2341576733540283,
|
||||
1.233040257804744
|
||||
],
|
||||
"sigma68_1d_um": [
|
||||
0.8577781558036803,
|
||||
0.8123240303993223,
|
||||
0.7792949676513672,
|
||||
0.7739067077636719,
|
||||
0.7715650343894959,
|
||||
0.7624583315849303,
|
||||
0.7544517517089844,
|
||||
0.7504940032958984,
|
||||
0.7524013519287109,
|
||||
0.7503747940063477,
|
||||
0.7458209991455078,
|
||||
0.7477760314941406,
|
||||
0.7470074391365051,
|
||||
0.7445335388183594,
|
||||
0.7444691777229305,
|
||||
0.74462890625,
|
||||
0.7469968581199644,
|
||||
0.737730908393859,
|
||||
0.7428169250488281,
|
||||
0.7399559020996094,
|
||||
0.7451674020290372,
|
||||
0.7429361343383789,
|
||||
0.7429836583137512,
|
||||
0.7400032663345337,
|
||||
0.7349491119384766,
|
||||
0.7413864135742188,
|
||||
0.7349491119384766,
|
||||
0.7387638092041016,
|
||||
0.7363319396972656,
|
||||
0.7315158843994141,
|
||||
0.7396697998046875,
|
||||
0.7327079772949219,
|
||||
0.7345676422119141,
|
||||
0.7363796234130859,
|
||||
0.7356643676757812,
|
||||
0.7356166839599609,
|
||||
0.7392006599903106,
|
||||
0.7273197174072266,
|
||||
0.730133056640625,
|
||||
0.7278919219970703,
|
||||
0.7254123687744141,
|
||||
0.7317543029785156,
|
||||
0.7262945175170898,
|
||||
0.7277011871337891,
|
||||
0.7242202758789062,
|
||||
0.7252216339111328,
|
||||
0.7256474280357361,
|
||||
0.7262706756591797,
|
||||
0.7274356091022491,
|
||||
0.7245063781738281,
|
||||
0.7229804992675781,
|
||||
0.721891703605651,
|
||||
0.7235050201416016,
|
||||
0.7220555377006527,
|
||||
0.7221221923828125,
|
||||
0.7217884063720703,
|
||||
0.7205397200584412,
|
||||
0.7222652435302734,
|
||||
0.721471973657608,
|
||||
0.7233142852783203,
|
||||
0.72174072265625,
|
||||
0.7203102111816406,
|
||||
0.720498030185699,
|
||||
0.718772704601288,
|
||||
0.7185935974121094,
|
||||
0.7194995880126953,
|
||||
0.7213115692138672,
|
||||
0.7187366485595703,
|
||||
0.7188320159912109,
|
||||
0.7208824157714844,
|
||||
0.7189750671386719,
|
||||
0.7186412811279297,
|
||||
0.7197380065917969,
|
||||
0.7207393646240234,
|
||||
0.7204055786132812,
|
||||
0.7207411158084869,
|
||||
0.7184820950031281,
|
||||
0.7184982299804688,
|
||||
0.7184982299804688,
|
||||
0.7180213928222656,
|
||||
0.7184401273727409,
|
||||
0.7188081741333008,
|
||||
0.7189750671386719,
|
||||
0.7185960149765012,
|
||||
0.7188796997070312,
|
||||
0.7185935974121094,
|
||||
0.7174215054512024,
|
||||
0.7190227508544922,
|
||||
0.717616081237793,
|
||||
0.7184982299804688,
|
||||
0.7181166005134583,
|
||||
0.7170677185058594,
|
||||
0.7177993130683895,
|
||||
0.7177829742431641,
|
||||
0.7178783416748047,
|
||||
0.7189273834228516,
|
||||
0.7178735756874083,
|
||||
0.7168292999267578,
|
||||
0.7180690765380859,
|
||||
0.7174968719482422,
|
||||
0.7183074951171875,
|
||||
0.7174015045166016,
|
||||
0.7176876068115234,
|
||||
0.71810605764389,
|
||||
0.7181167602539062,
|
||||
0.7181310892105095,
|
||||
0.7179121041297913,
|
||||
0.7177352905273438,
|
||||
0.7172346115112305,
|
||||
0.7172107696533203,
|
||||
0.717592542171478,
|
||||
0.7175445556640625,
|
||||
0.7170200347900391,
|
||||
0.7170084071159364,
|
||||
0.7172584533691406,
|
||||
0.7172584533691406,
|
||||
0.7176580929756162,
|
||||
0.7176608490943904,
|
||||
0.7172107696533203,
|
||||
0.7176876068115234,
|
||||
0.7177377080917355,
|
||||
0.7169246673583984,
|
||||
0.7174783635139466,
|
||||
0.7172584533691406,
|
||||
0.7175922393798828,
|
||||
0.7175445556640625,
|
||||
0.7172346115112305,
|
||||
0.7173299789428711,
|
||||
0.7171154022216797,
|
||||
0.7173206448554993,
|
||||
0.7172107696533203,
|
||||
0.7170677185058594,
|
||||
0.7173061370849609,
|
||||
0.7171869277954102,
|
||||
0.7168769836425781,
|
||||
0.7170677185058594,
|
||||
0.7170677185058594,
|
||||
0.7171714866161347,
|
||||
0.7170677185058594,
|
||||
0.7173142266273497,
|
||||
0.7172584533691406,
|
||||
0.7173061370849609,
|
||||
0.7170677185058594,
|
||||
0.7172298645973206,
|
||||
0.7173061370849609,
|
||||
0.7171869277954102,
|
||||
0.7173299789428711,
|
||||
0.7172990965843201,
|
||||
0.7171154022216797,
|
||||
0.717473030090332
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 411 KiB |
|
After Width: | Height: | Size: 152 KiB |
|
After Width: | Height: | Size: 238 KiB |
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 74 KiB |
@@ -0,0 +1,56 @@
|
||||
experiment:
|
||||
name: poly5to30keV_Moench014
|
||||
results_dir: Results
|
||||
data:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/GridBased/poly5to30keV_Moench014_150V
|
||||
train_shards:
|
||||
- 0
|
||||
- 11
|
||||
val_shards:
|
||||
- 0
|
||||
- 1
|
||||
max_train_frames: null
|
||||
max_val_frames: 8000
|
||||
input_scale: 15.0
|
||||
energy_scale: 15.0
|
||||
augment: true
|
||||
batch_size_train: 256
|
||||
batch_size_val: 512
|
||||
num_workers: 8
|
||||
model:
|
||||
channels:
|
||||
- 32
|
||||
- 64
|
||||
- 128
|
||||
- 128
|
||||
predict_energy: true
|
||||
norm: none
|
||||
prior_prob: 0.01
|
||||
loss:
|
||||
w_obj: 1.0
|
||||
w_off: 1.0
|
||||
w_ene: 1.0
|
||||
focal_alpha: 0.25
|
||||
focal_gamma: 2.0
|
||||
smooth_l1_beta_offset: 0.01
|
||||
smooth_l1_beta_energy: 0.03
|
||||
training:
|
||||
epochs: 300
|
||||
lr: 0.001
|
||||
weight_decay: 0.0
|
||||
scheduler_factor: 0.5
|
||||
scheduler_patience: 6
|
||||
amp: true
|
||||
seed: 0
|
||||
checkpoint_epochs:
|
||||
- 50
|
||||
- 100
|
||||
- 150
|
||||
- 200
|
||||
- 250
|
||||
- 300
|
||||
eval:
|
||||
threshold: 0.3
|
||||
merge_distance: 0.1
|
||||
match_radius: 1.0
|
||||
pixel_size_um: 25.0
|
||||
|
After Width: | Height: | Size: 410 KiB |
|
After Width: | Height: | Size: 158 KiB |
|
After Width: | Height: | Size: 239 KiB |
|
After Width: | Height: | Size: 173 KiB |
|
After Width: | Height: | Size: 74 KiB |
@@ -0,0 +1,56 @@
|
||||
experiment:
|
||||
name: poly3to30keV_Moench014_c128
|
||||
results_dir: Results
|
||||
data:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/GridBased/poly3to30keV_Moench014_150V
|
||||
train_shards:
|
||||
- 0
|
||||
- 11
|
||||
val_shards:
|
||||
- 0
|
||||
- 1
|
||||
max_train_frames: null
|
||||
max_val_frames: 8000
|
||||
input_scale: 15.0
|
||||
energy_scale: 15.0
|
||||
augment: true
|
||||
batch_size_train: 256
|
||||
batch_size_val: 512
|
||||
num_workers: 8
|
||||
model:
|
||||
channels:
|
||||
- 32
|
||||
- 64
|
||||
- 128
|
||||
- 128
|
||||
predict_energy: true
|
||||
norm: none
|
||||
prior_prob: 0.01
|
||||
loss:
|
||||
w_obj: 1.0
|
||||
w_off: 1.0
|
||||
w_ene: 1.0
|
||||
focal_alpha: 0.25
|
||||
focal_gamma: 2.0
|
||||
smooth_l1_beta_offset: 0.01
|
||||
smooth_l1_beta_energy: 0.03
|
||||
training:
|
||||
epochs: 300
|
||||
lr: 0.001
|
||||
weight_decay: 0.0
|
||||
scheduler_factor: 0.5
|
||||
scheduler_patience: 6
|
||||
amp: true
|
||||
seed: 0
|
||||
checkpoint_epochs:
|
||||
- 50
|
||||
- 100
|
||||
- 150
|
||||
- 200
|
||||
- 250
|
||||
- 300
|
||||
eval:
|
||||
threshold: 0.3
|
||||
merge_distance: 0.1
|
||||
match_radius: 1.0
|
||||
pixel_size_um: 25.0
|
||||
|
After Width: | Height: | Size: 412 KiB |
|
After Width: | Height: | Size: 158 KiB |
|
After Width: | Height: | Size: 239 KiB |
|
After Width: | Height: | Size: 172 KiB |
|
After Width: | Height: | Size: 72 KiB |
@@ -0,0 +1,56 @@
|
||||
experiment:
|
||||
name: poly3to30keV_Moench014_c64
|
||||
results_dir: Results
|
||||
data:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/GridBased/poly3to30keV_Moench014_150V
|
||||
train_shards:
|
||||
- 0
|
||||
- 11
|
||||
val_shards:
|
||||
- 0
|
||||
- 1
|
||||
max_train_frames: null
|
||||
max_val_frames: 8000
|
||||
input_scale: 15.0
|
||||
energy_scale: 15.0
|
||||
augment: true
|
||||
batch_size_train: 256
|
||||
batch_size_val: 512
|
||||
num_workers: 8
|
||||
model:
|
||||
channels:
|
||||
- 32
|
||||
- 64
|
||||
- 64
|
||||
- 64
|
||||
predict_energy: true
|
||||
norm: none
|
||||
prior_prob: 0.01
|
||||
loss:
|
||||
w_obj: 1.0
|
||||
w_off: 1.0
|
||||
w_ene: 1.0
|
||||
focal_alpha: 0.25
|
||||
focal_gamma: 2.0
|
||||
smooth_l1_beta_offset: 0.01
|
||||
smooth_l1_beta_energy: 0.03
|
||||
training:
|
||||
epochs: 300
|
||||
lr: 0.001
|
||||
weight_decay: 0.0
|
||||
scheduler_factor: 0.5
|
||||
scheduler_patience: 6
|
||||
amp: true
|
||||
seed: 0
|
||||
checkpoint_epochs:
|
||||
- 50
|
||||
- 100
|
||||
- 150
|
||||
- 200
|
||||
- 250
|
||||
- 300
|
||||
eval:
|
||||
threshold: 0.3
|
||||
merge_distance: 0.1
|
||||
match_radius: 1.0
|
||||
pixel_size_um: 25.0
|
||||
|
After Width: | Height: | Size: 405 KiB |
|
After Width: | Height: | Size: 156 KiB |
|
After Width: | Height: | Size: 239 KiB |
|
After Width: | Height: | Size: 172 KiB |
|
After Width: | Height: | Size: 78 KiB |
@@ -0,0 +1,56 @@
|
||||
experiment:
|
||||
name: poly3to30keV_Moench014_c96
|
||||
results_dir: Results
|
||||
data:
|
||||
folder: /mnt/sls_det_storage/moench_data/MLXID/Samples/GridBased/poly3to30keV_Moench014_150V
|
||||
train_shards:
|
||||
- 0
|
||||
- 11
|
||||
val_shards:
|
||||
- 0
|
||||
- 1
|
||||
max_train_frames: null
|
||||
max_val_frames: 8000
|
||||
input_scale: 15.0
|
||||
energy_scale: 15.0
|
||||
augment: true
|
||||
batch_size_train: 256
|
||||
batch_size_val: 512
|
||||
num_workers: 8
|
||||
model:
|
||||
channels:
|
||||
- 32
|
||||
- 64
|
||||
- 96
|
||||
- 96
|
||||
predict_energy: true
|
||||
norm: none
|
||||
prior_prob: 0.01
|
||||
loss:
|
||||
w_obj: 1.0
|
||||
w_off: 1.0
|
||||
w_ene: 1.0
|
||||
focal_alpha: 0.25
|
||||
focal_gamma: 2.0
|
||||
smooth_l1_beta_offset: 0.01
|
||||
smooth_l1_beta_energy: 0.03
|
||||
training:
|
||||
epochs: 300
|
||||
lr: 0.001
|
||||
weight_decay: 0.0
|
||||
scheduler_factor: 0.5
|
||||
scheduler_patience: 6
|
||||
amp: true
|
||||
seed: 0
|
||||
checkpoint_epochs:
|
||||
- 50
|
||||
- 100
|
||||
- 150
|
||||
- 200
|
||||
- 250
|
||||
- 300
|
||||
eval:
|
||||
threshold: 0.3
|
||||
merge_distance: 0.1
|
||||
match_radius: 1.0
|
||||
pixel_size_um: 25.0
|
||||
|
After Width: | Height: | Size: 419 KiB |
|
After Width: | Height: | Size: 159 KiB |
|
After Width: | Height: | Size: 230 KiB |
|
After Width: | Height: | Size: 171 KiB |