Skip to main content

2-D Image Benchmarks

These reports measure complete image-combination workflows and identify the builds, environment, and settings used. Timings apply to those workloads and that machine. See performance tuning for workspace and thread choices.

The reproduction guide contains the commands and settings for the measurements taken on 2026-09-08 UTC. Build identities are recorded in the measurement environment.

Image combination

The matrix contains 80 scenarios with (N, 512, 512) inputs: five dtypes (uint8, uint16, int16, int32, float32), N=5 or 31, four operations (mean, median, sigma-clipped mean, sigma-clipped median), and masked/unmasked inputs. Masked scenarios exclude a deterministic random 2% of pixels per frame.

Column Measured route
imc Standard Combiner on the original input dtype; rejection rows request only the combined image with diagnostics=None.
imc_chain Chained Combiner; rejection rows retain rejection diagnostics and pipeline state. Simple rows use the same route as imc.
imc_opt Direct calls on an already prepared contiguous float workspace with validate=False. Plain reductions use reducers; rejection rows use the fused sigma-clipping adapter.
np_ap NumPy nanmean/nanmedian, or Astropy sigma_clip followed by a NumPy reduction.
ccdproc Construction of CCDData inputs and ccdproc.Combiner, followed by clipping when requested and the final reduction.

Times are milliseconds. Each */opt column divides that route’s time by imc_opt; a value above 1 means the prepared direct route was faster for that row. Its workspace conversion and contiguity preparation are excluded from timing. Mask materialization for its plain reductions remains inside the timed call. Public routes include their normal input preparation.

Before timing, imc, imc_chain, and imc_opt are checked against the NumPy/Astropy reference. Shapes and nonfinite values must match exactly. Finite values use rtol=1e-5 and atol=1e-4, with at most a 1e-5 fraction of output pixels outside that tolerance. The reference uses a float32 workspace; imcombiners promotes int32 inputs to float64.

Sigma-clipping settings are sigma=(3, 3), maxiters=5, ddof=0, nkeep=0, cenfunc="median", and clip_cen="mean". The ccdproc route uses its public one-iteration clipping behavior. Its output differences are informational rather than a parity requirement; † marks rows that exceed the comparison tolerance. The image harness contains the input generation, validation, and timing code.

Measured 2026-09-08 UTC using release builds. Rayon: 14 threads; reducers grains: built-in defaults; BLAS/OpenMP limits: 1 thread. Median of 5 repeats after 1 warmup per route. Times are milliseconds.

Environment

item value
Python 3.13.11
Kernel/OS macOS-26.6-arm64-arm-64bit-Mach-O
Machine arm64
Processor arm
Logical CPUs 14
imcombiners 0.1.2
reducers 0.4.0
numpy 2.5.2
bottleneck 1.6.0
astropy 7.2.0
ccdproc 2.5.1
fitsio 1.3.0
reducers (Rust) 0.4.0
reducers (Rust source) path

No Mask

Simple

op dtype N imc imc_chain imc_opt np_ap ccdproc imc/opt chain/opt np_ap/opt ccd/opt
mean uint8 5 0.80 0.79 0.30 1.55 3.63 2.6 2.6 5.1 12.1
median uint8 5 1.54 1.53 1.16 24.87 59.38 1.3 1.3 21.4 51.0
mean uint8 31 3.41 3.38 1.05 8.36 31.29 3.3 3.2 8.0 29.9
median uint8 31 8.27 8.19 5.81 246.43 572.65 1.4 1.4 42.4 98.6
mean uint16 5 0.67 0.69 0.28 1.53 3.63 2.4 2.5 5.5 13.1
median uint16 5 1.51 1.57 1.19 24.59 59.16 1.3 1.3 20.7 49.8
mean uint16 31 3.40 3.37 1.01 8.37 31.52 3.4 3.3 8.3 31.2
median uint16 31 7.96 8.58 6.06 247.29 581.19 1.3 1.4 40.8 95.8
mean int16 5 0.67 0.66 0.31 1.56 3.64 2.1 2.1 5.0 11.7
median int16 5 1.56 1.59 1.15 24.77 59.32 1.4 1.4 21.5 51.5
mean int16 31 3.35 3.71 1.12 8.36 31.36 3.0 3.3 7.5 28.0
median int16 31 7.79 8.16 6.05 249.03 583.04 1.3 1.3 41.2 96.4
mean int32 5 0.83 0.78 0.29 1.53 3.67 2.9 2.7 5.3 12.7
median int32 5 1.73 1.72 1.13 24.22 58.37 1.5 1.5 21.4 51.6
mean int32 31 4.02 3.80 1.01 8.19 30.92 4.0 3.8 8.1 30.6
median int32 31 8.56 8.90 6.11 230.91 547.95 1.4 1.5 37.8 89.6
mean float32 5 0.34 0.34 0.29 1.20 3.22 1.2 1.2 4.1 11.1
median float32 5 1.22 1.21 1.17 23.55 57.25 1.0 1.0 20.1 48.8
mean float32 31 1.31 1.24 0.73 6.25 29.37 1.8 1.7 8.5 40.0
median float32 31 5.69 5.96 5.66 228.84 547.26 1.0 1.1 40.4 96.7

Sigclip

sigma=(3, 3), maxiters=5, ddof=0, nkeep=0, cenfunc="median", clip_cen="mean". ccdproc uses maxiters=1 †.

op dtype N imc imc_chain imc_opt np_ap ccdproc imc/opt chain/opt np_ap/opt ccd/opt
sigclip_mean uint8 5 2.72 3.89 2.22 12.92 18.35 1.22 1.75 5.82 8.26
sigclip_median uint8 5 2.48 4.66 2.08 36.47 73.80 1.20 2.24 17.56 35.53
sigclip_mean uint8 31 9.68 51.81 7.38 119.00 158.37† 1.31 7.02 16.12 21.46
sigclip_median uint8 31 9.92 58.29 7.80 359.58 703.96† 1.27 7.47 46.11 90.27
sigclip_mean uint16 5 2.92 3.96 2.38 12.98 18.60 1.23 1.66 5.45 7.80
sigclip_median uint16 5 2.62 4.94 2.05 36.05 74.27 1.28 2.42 17.62 36.30
sigclip_mean uint16 31 9.65 46.96 7.38 123.92 162.81† 1.31 6.36 16.79 22.06
sigclip_median uint16 31 9.76 50.89 7.66 363.65 717.78† 1.27 6.65 47.49 93.74
sigclip_mean int16 5 2.65 3.76 2.20 12.96 18.37 1.21 1.71 5.89 8.34
sigclip_median int16 5 2.50 4.65 2.09 35.62 73.16 1.20 2.23 17.03 34.98
sigclip_mean int16 31 9.25 45.96 7.00 118.35 158.72† 1.32 6.56 16.90 22.66
sigclip_median int16 31 8.89 51.81 7.09 347.54 685.60† 1.25 7.31 49.00 96.67
sigclip_mean int32 5 2.45 3.66 1.94 12.59 17.98 1.27 1.89 6.50 9.29
sigclip_median int32 5 2.30 4.28 1.80 35.43 73.11 1.28 2.38 19.72 40.68
sigclip_mean int32 31 10.04 45.82 7.30 118.95 157.02† 1.37 6.27 16.29 21.50
sigclip_median int32 31 9.57 49.18 7.14 341.22 679.57† 1.34 6.89 47.80 95.20
sigclip_mean float32 5 1.98 3.06 1.90 12.27 17.64 1.04 1.61 6.46 9.29
sigclip_median float32 5 1.89 3.93 1.80 34.95 72.42 1.05 2.19 19.45 40.30
sigclip_mean float32 31 7.25 44.42 6.75 114.93 155.41† 1.07 6.58 17.02 23.02
sigclip_median float32 31 6.69 50.63 7.26 339.28 683.47† 0.92 6.97 46.71 94.09

With Mask (~2% pixels masked per frame)

Simple

op dtype N imc imc_chain imc_opt np_ap ccdproc imc/opt chain/opt np_ap/opt ccd/opt
mean uint8 5 1.24 1.29 0.69 2.17 3.59 1.8 1.9 3.2 5.2
median uint8 5 2.11 2.10 2.00 25.43 60.46 1.1 1.1 12.7 30.3
mean uint8 31 7.08 7.08 3.58 12.68 31.26 2.0 2.0 3.5 8.7
median uint8 31 10.81 10.83 8.15 235.46 545.91 1.3 1.3 28.9 67.0
mean uint16 5 1.26 1.23 0.68 2.21 3.62 1.9 1.8 3.3 5.3
median uint16 5 2.03 2.02 1.70 24.87 59.91 1.2 1.2 14.7 35.3
mean uint16 31 7.10 7.18 3.63 12.69 31.20 2.0 2.0 3.5 8.6
median uint16 31 11.33 11.15 8.28 237.81 555.99 1.4 1.3 28.7 67.1
mean int16 5 1.23 1.26 0.67 2.15 3.58 1.8 1.9 3.2 5.4
median int16 5 1.99 2.10 1.68 25.74 59.01 1.2 1.3 15.3 35.2
mean int16 31 7.20 7.05 3.45 12.66 31.19 2.1 2.0 3.7 9.0
median int16 31 11.29 10.93 8.26 235.12 552.20 1.4 1.3 28.5 66.9
mean int32 5 1.37 1.37 0.70 2.19 3.62 1.9 1.9 3.1 5.1
median int32 5 2.28 2.21 1.98 25.66 59.56 1.2 1.1 13.0 30.1
mean int32 31 8.37 8.31 3.68 12.62 31.24 2.3 2.3 3.4 8.5
median int32 31 12.92 12.94 8.95 236.45 551.56 1.4 1.4 26.4 61.6
mean float32 5 0.92 0.94 0.67 1.92 3.32 1.4 1.4 2.9 4.9
median float32 5 1.75 1.68 1.73 23.79 59.09 1.0 1.0 13.8 34.2
mean float32 31 5.04 5.00 3.82 11.05 29.43 1.3 1.3 2.9 7.7
median float32 31 9.10 9.58 8.51 234.46 551.62 1.1 1.1 27.6 64.8

Sigclip

sigma=(3, 3), maxiters=5, ddof=0, nkeep=0, cenfunc="median", clip_cen="mean". ccdproc uses maxiters=1 †.

op dtype N imc imc_chain imc_opt np_ap ccdproc imc/opt chain/opt np_ap/opt ccd/opt
sigclip_mean uint8 5 3.05 4.25 2.12 13.89 17.88 1.44 2.01 6.57 8.46
sigclip_median uint8 5 2.95 5.24 1.98 37.32 74.53 1.49 2.65 18.84 37.63
sigclip_mean uint8 31 13.83 48.13 8.10 124.87 151.41† 1.71 5.94 15.41 18.69
sigclip_median uint8 31 13.88 49.34 8.12 348.98 665.81† 1.71 6.08 42.97 81.98
sigclip_mean uint16 5 3.12 4.33 2.13 13.60 17.95 1.46 2.03 6.37 8.41
sigclip_median uint16 5 2.99 5.29 2.14 37.14 74.63 1.40 2.47 17.34 34.85
sigclip_mean uint16 31 14.12 47.05 8.28 126.16 156.97† 1.71 5.69 15.25 18.97
sigclip_median uint16 31 14.30 55.85 8.45 346.58 678.11† 1.69 6.61 41.02 80.26
sigclip_mean int16 5 3.15 4.30 2.18 13.55 17.84 1.44 1.97 6.21 8.17
sigclip_median int16 5 3.02 5.15 2.20 37.02 74.07 1.37 2.34 16.86 33.72
sigclip_mean int16 31 14.19 48.93 8.75 125.12 155.17† 1.62 5.59 14.30 17.73
sigclip_median int16 31 14.24 55.49 8.43 348.88 675.24† 1.69 6.58 41.37 80.08
sigclip_mean int32 5 3.16 4.42 2.12 13.72 18.02 1.49 2.08 6.47 8.50
sigclip_median int32 5 3.10 5.42 1.98 37.05 74.11 1.56 2.74 18.71 37.43
sigclip_mean int32 31 15.11 52.88 8.65 126.28 155.04† 1.75 6.12 14.61 17.93
sigclip_median int32 31 15.87 57.24 8.31 352.16 673.75† 1.91 6.89 42.37 81.06
sigclip_mean float32 5 2.81 4.03 2.21 13.56 17.66 1.28 1.83 6.15 8.01
sigclip_median float32 5 2.74 4.97 2.12 37.22 73.19 1.29 2.35 17.57 34.55
sigclip_mean float32 31 12.15 46.52 8.09 124.93 153.32† 1.50 5.75 15.44 18.94
sigclip_median float32 31 12.71 54.27 8.13 346.55 673.38† 1.56 6.67 42.62 82.81

IRAF compatibility

The IRAF matrix contains 96 cases with seven 512×512 images and uint16, int16, or float32 inputs. It combines mean/median with sigclip, ccdclip, pclip, and minmax. Per-case rows cover baseline, threshold, input-BPM, CCD sensitivity-noise, and supported scale/zero variants. Grouped rows measure throughput for the complete matrix and each rejection method.

Output-only ndcombine(..., diagnostics=None) results are validated against IRAF before timing. Timings include FITS input reads, stacking, combination, and combined FITS output writes. The IRAF compatibility tutorial describes the supported settings and task-tree setup; the IRAF harness implements the comparison.

IMC times are medians of separate workload repeats. IRAF runs the repeated workload in one CL process and divides the elapsed batch duration by the repeat count. This applies to both one-case and grouped rows. With the recorded tiny-imcombine baseline mode, the median duration of a 1×1 output-only IRAF task is subtracted once per CL process before division. The baseline is measured per dtype; mixed-dtype groups use the first case’s dtype. The IRAF/imc ratio therefore compares these two timing procedures, including FITS I/O.

Measured 2026-09-08 UTC using release builds. Rayon: 14 threads; reducers grains: built-in defaults; BLAS/OpenMP limits: 1 thread.

Run setting Value
Repeats 3
Input shape 512x512
IRAF baseline mode tiny-imcombine
Subtracted IRAF baseline float32=113.539, int16=113.789, uint16=109.642 ms
Validation output-only imc results asserted against IRAF before timing

Environment

item value
Python 3.13.11
Kernel/OS macOS-26.6-arm64-arm-64bit-Mach-O
Machine arm64
Processor arm
Logical CPUs 14
imcombiners 0.1.2
reducers 0.4.0
numpy 2.5.2
bottleneck 1.6.0
astropy 7.2.0
ccdproc 2.5.1
fitsio 1.3.0
reducers (Rust) 0.4.0
reducers (Rust source) path

Batched CL Throughput Timings

group cases IRAF ms imc ms IRAF/imc
all 96 1851.672 712.585 2.6x
sigclip 18 381.849 147.234 2.6x
ccdclip 30 598.761 229.934 2.6x
pclip 24 480.359 186.668 2.6x
minmax 24 408.619 178.234 2.3x

One-Case CL Timings

op dtype N variant imc ms IRAF ms IRAF/imc (speedup)
sigclip_mean uint16 7 baseline 6.838 17.311 2.5x
ccdclip_mean uint16 7 baseline 6.794 16.515 2.4x
pclip_mean uint16 7 baseline 6.599 17.483 2.6x
minmax_mean uint16 7 baseline 6.562 13.032 2.0x
sigclip_mean uint16 7 threshold 8.000 17.938 2.2x
ccdclip_mean uint16 7 threshold 8.583 18.672 2.2x
pclip_mean uint16 7 threshold 7.376 18.951 2.6x
minmax_mean uint16 7 threshold 7.104 13.540 1.9x
sigclip_mean uint16 7 input_bpm 10.963 28.412 2.6x
ccdclip_mean uint16 7 input_bpm 10.979 31.578 2.9x
pclip_mean uint16 7 input_bpm 11.727 29.428 2.5x
minmax_mean uint16 7 input_bpm 10.046 24.146 2.4x
ccdclip_mean uint16 7 snoise 6.774 17.337 2.6x
ccdclip_mean uint16 7 scaled 8.146 19.852 2.4x
pclip_mean uint16 7 scaled 7.314 17.197 2.4x
minmax_mean uint16 7 scaled 6.752 15.216 2.3x
sigclip_median uint16 7 baseline 7.051 17.748 2.5x
ccdclip_median uint16 7 baseline 6.857 18.219 2.7x
pclip_median uint16 7 baseline 6.733 18.132 2.7x
minmax_median uint16 7 baseline 6.231 14.341 2.3x
sigclip_median uint16 7 threshold 7.597 18.614 2.5x
ccdclip_median uint16 7 threshold 7.632 16.998 2.2x
pclip_median uint16 7 threshold 6.910 19.602 2.8x
minmax_median uint16 7 threshold 7.287 15.159 2.1x
sigclip_median uint16 7 input_bpm 10.661 28.443 2.7x
ccdclip_median uint16 7 input_bpm 10.609 27.864 2.6x
pclip_median uint16 7 input_bpm 10.717 28.495 2.7x
minmax_median uint16 7 input_bpm 10.269 25.870 2.5x
ccdclip_median uint16 7 snoise 7.084 17.930 2.5x
ccdclip_median uint16 7 scaled 7.199 18.081 2.5x
pclip_median uint16 7 scaled 7.704 18.107 2.4x
minmax_median uint16 7 scaled 7.136 14.816 2.1x
sigclip_mean int16 7 baseline 5.773 15.434 2.7x
ccdclip_mean int16 7 baseline 5.477 15.842 2.9x
pclip_mean int16 7 baseline 5.325 15.906 3.0x
minmax_mean int16 7 baseline 5.666 11.246 2.0x
sigclip_mean int16 7 threshold 6.561 19.288 2.9x
ccdclip_mean int16 7 threshold 6.503 17.398 2.7x
pclip_mean int16 7 threshold 6.141 16.411 2.7x
minmax_mean int16 7 threshold 6.177 12.257 2.0x
sigclip_mean int16 7 input_bpm 9.454 26.932 2.8x
ccdclip_mean int16 7 input_bpm 9.200 26.641 2.9x
pclip_mean int16 7 input_bpm 9.732 27.420 2.8x
minmax_mean int16 7 input_bpm 8.866 24.017 2.7x
ccdclip_mean int16 7 snoise 5.627 15.378 2.7x
ccdclip_mean int16 7 scaled 5.812 18.943 3.3x
pclip_mean int16 7 scaled 6.162 17.010 2.8x
minmax_mean int16 7 scaled 5.489 11.117 2.0x
sigclip_median int16 7 baseline 5.821 14.691 2.5x
ccdclip_median int16 7 baseline 5.751 18.674 3.2x
pclip_median int16 7 baseline 5.644 17.077 3.0x
minmax_median int16 7 baseline 5.674 13.534 2.4x
sigclip_median int16 7 threshold 6.369 15.856 2.5x
ccdclip_median int16 7 threshold 6.423 15.897 2.5x
pclip_median int16 7 threshold 6.278 15.746 2.5x
minmax_median int16 7 threshold 6.115 13.412 2.2x
sigclip_median int16 7 input_bpm 9.377 26.873 2.9x
ccdclip_median int16 7 input_bpm 9.468 26.155 2.8x
pclip_median int16 7 input_bpm 9.352 26.866 2.9x
minmax_median int16 7 input_bpm 9.191 24.032 2.6x
ccdclip_median int16 7 snoise 6.076 14.077 2.3x
ccdclip_median int16 7 scaled 6.866 18.634 2.7x
pclip_median int16 7 scaled 6.149 15.909 2.6x
minmax_median int16 7 scaled 6.285 13.671 2.2x
sigclip_mean float32 7 baseline 7.635 16.558 2.2x
ccdclip_mean float32 7 baseline 7.239 16.394 2.3x
pclip_mean float32 7 baseline 7.875 16.953 2.2x
minmax_mean float32 7 baseline 6.939 13.088 1.9x
sigclip_mean float32 7 threshold 8.620 17.016 2.0x
ccdclip_mean float32 7 threshold 8.241 17.346 2.1x
pclip_mean float32 7 threshold 8.133 18.498 2.3x
minmax_mean float32 7 threshold 8.029 15.460 1.9x
sigclip_mean float32 7 input_bpm 11.300 28.200 2.5x
ccdclip_mean float32 7 input_bpm 11.261 28.154 2.5x
pclip_mean float32 7 input_bpm 11.126 28.155 2.5x
minmax_mean float32 7 input_bpm 10.595 24.506 2.3x
ccdclip_mean float32 7 snoise 7.898 15.683 2.0x
ccdclip_mean float32 7 scaled 8.621 19.985 2.3x
pclip_mean float32 7 scaled 8.037 16.854 2.1x
minmax_mean float32 7 scaled 6.943 12.352 1.8x
sigclip_median float32 7 baseline 7.347 15.866 2.2x
ccdclip_median float32 7 baseline 7.471 15.376 2.1x
pclip_median float32 7 baseline 7.618 16.300 2.1x
minmax_median float32 7 baseline 6.537 14.168 2.2x
sigclip_median float32 7 threshold 8.392 16.939 2.0x
ccdclip_median float32 7 threshold 9.523 17.146 1.8x
pclip_median float32 7 threshold 13.703 18.270 1.3x
minmax_median float32 7 threshold 8.173 20.620 2.5x
sigclip_median float32 7 input_bpm 12.343 28.890 2.3x
ccdclip_median float32 7 input_bpm 12.889 26.864 2.1x
pclip_median float32 7 input_bpm 10.813 29.975 2.8x
minmax_median float32 7 input_bpm 11.101 28.984 2.6x
ccdclip_median float32 7 snoise 7.559 16.034 2.1x
ccdclip_median float32 7 scaled 8.167 18.825 2.3x
pclip_median float32 7 scaled 8.243 17.596 2.1x
minmax_median float32 7 scaled 7.645 14.977 2.0x