diff --git a/index.html b/index.html index 21546fb..49473e7 100644 --- a/index.html +++ b/index.html @@ -130,7 +130,7 @@
Version 5.0.1 — available now
+Version 5.1.1 — available now
The analysis workflow is finished and covered by automated tests, including parity harnesses measured against py4DSTEM on experimental data.
Version 5.0.1 is available as a signed, notarized disk image. Open it and drag mac4DSTEM to your Applications folder — it launches without a security warning, and needs nothing else installed.
+Version 5.1.1 is available as a signed, notarized disk image. Open it and drag mac4DSTEM to your Applications folder — it launches without a security warning, and needs nothing else installed.
- Requires macOS 27 or later on Apple silicon (for macOS 14–26, version 3.0.0 remains available). No external runtime, toolchain, or library + Requires macOS 26 or later on Apple silicon (for macOS 14–25, version 3.0.0 remains available). No external runtime, toolchain, or library installation is needed — all dependencies are contained within the application. The Merlin MIB and EMPAD RAW readers are preview-grade pending further vendor data.
@@ -417,10 +417,10 @@Version 1.0.0 · part of the macEM suite, beside mac4DSTEM
+Version 1.1.1 · part of the macEM suite, beside mac4DSTEM
Today every function above is CPU (Accelerate, Float64 reference plus Float32 where it exists). No function has a Metal path, so no Metal break-even has been measured; the column says what the CPU table implies and what a large-size run must measure. A guess is not recorded as a measurement.
| function | backend today | decision |
|---|---|---|
fft2 Float32/Float64 | CPU | CPU only at 128² to 512² (0.02 to 2 ms: a Metal dispatch cannot win). Float64 lengths of prime factors 2, 3, 5, 7 run on the mixed-radix plan. Work item: a Metal Float32 FFT prototype, break-even not measured yet (2048², 4096², 8192²) |
rfft2, irfft2, butterworth, masked registration | CPU | CPU; real-input transform since 2026-10-22 (0.7 ms Float64 at 512², 1.1 times NumPy); a Metal path would have to beat 0.4 to 0.7 ms at 512², which a dispatch cannot, so the break-even is again a question for 2048² and up, not measured yet |
gaussian_filter, uniform_filter, difference_of_gaussians | CPU | CPU only at 128² to 512² (1 to 4 ms, memory bound). Metal candidate above 2048² for large sigma; not measured yet |
shift order 1 | CPU | CPU only: 0.65 ms at 512² |
shift order 3 (prefilter plus taps) | CPU | CPU; the prefilter is sequential along lines, the tap sum is the Metal-friendly part: candidate above 2048², not measured |
phase_cross_correlation | CPU | CPU; FFT-bound, follows fft2 |
profile_line | CPU | CPU: small arrays stay on the CPU |
label | CPU | CPU: union-find is not a Metal workload |
peak_local_max | CPU | CPU; the window maximum is a Metal candidate only above 4096² |
Measured 2026-10-21. Small and typical sizes only; the large rows are not measured yet (they run with DIFFRACTO_BENCH_LARGE=1). Best of five after one warm-up: the median is the figure, the spread (min-max) is in brackets. Same inputs on both sides (tools/benchmarks/gen_inputs.py writes them), Float64 unless the function is Float32 by design (ACOM, ellipse pattern pixels).
| Machine | Apple M5 Pro, 64 GB, macOS 27.0.1 (Darwin 27.0.0) |
| Toolchain | Apple Swift 6.4, swift build -c release (separate package tools/benchmarks) |
| Python | 3.12.14, NumPy 2.5.4, SciPy 1.18.1, in two virtual environments: py4DSTEM 0.14.19 in one; pymatgen-core 2026.10.16 (the code; its pymatgen metapackage dist-info reads 2026.9.24), orix 0.15.0 and spglib 2.8.0 in the other |
| Load | 10.5 on a 12-core machine while other builds ran (uptime 17:39): every figure carries that noise, the single-core rows least. Re-run when the machine is quiet before quoting a ratio. |
| Pin note | The orix environment runs pymatgen-core 2026.10.16 under a pymatgen 2026.9.24 metapackage; the fixtures record pymatgen 2026.9.24 and, except cif-symmetry-pins.json (generated 2026-10-21 on this install, byte-identical on regeneration), pymatgen-core 2026.9.23. Nothing here compares numbers, only time |
| 0.9.1 | The symmetry_detection and cif_import rows above are the 2026-10-21 measurement of 0.9.0. 0.9.1 replaced the closure check that took 95 % of them (see docs/open-items.md); measured in-process on the same al_super2.cif (machine load 3.6): cif_import typical median 67 ms (min 67, max 77), against 297 ms (one run at load 9) before the change and the table's 351 ms. Not yet re-run through run.sh |
| Machine | Apple M5 Pro, 64 GB, macOS 27.0.1 (Darwin 27.0.0) |
| Toolchain | Apple Swift 6.4, swift build -c release (separate package tools/benchmarks) |
| Python | 3.12.14, NumPy 2.5.4, SciPy 1.18.1, in two virtual environments: py4DSTEM 0.14.19 in one; pymatgen-core 2026.10.16 (the code; its pymatgen metapackage dist-info reads 2026.9.24), orix 0.15.0 and spglib 2.8.0 in the other |
| Load | 10.5 on a 12-core machine while other builds ran (uptime 17:39): every figure carries that noise, the single-core rows least. Re-run when the machine is quiet before quoting a ratio. |
| Pin note | The pymatgen environment runs pymatgen-core 2026.10.16 under a pymatgen 2026.9.24 metapackage, and every fixture that records pymatgen-core records 2026.10.16 (tools/pins/requirements/pymatgen.txt). Nothing here compares numbers, only time |
| 0.9.1 | The symmetry_detection and cif_import rows above are the 2026-10-21 measurement of 0.9.0. 0.9.1 replaced the closure check that took 95 % of them (see docs/parity.md, known limits); measured in-process on the same al_super2.cif (machine load 3.6): cif_import typical median 67 ms (min 67, max 77), against 297 ms (one run at load 9) before the change and the table's 351 ms. Not yet re-run through run.sh |
Re-run from a fresh clone of the kit, on a quiet Mac: gen_inputs.py writes the shared inputs, run.sh builds the benchmark package (tools/benchmarks, release) and prints the kit's JSON lines, bench_python.py prints the Python lines, and merge.py turns them into the table below. Add DIFFRACTO_BENCH_LARGE=1 to run.sh and bench_python.py for the large rows.
The raw lines of the run below are tools/benchmarks/results/2026-10-21.jsonl.
acom_match_scan is ms per pattern)kinematic_reflections: the kit's kinematicReflections(kMax:retainingAll:false) against py4DSTEM's
Crystal.calculate_structure_factors on the same C2/m cell; the kit is 1.8 to 4.5 times faster. Both use the Lobato-Van Dyck table.
symmetry_detection and cif_import: the kit's CIFImport.read always detects the symmetry of the cell it reads;
pymatgen's CifParser only parses and SpacegroupAnalyzer is spglib in C. On a 32-atom P1 cell (an fcc supercell with 1 536 operations) the kit took 361 ms against 13 ms, 28 times slower; on a four-atom cell they are level. The cause was the closure check, not the symmetry search (docs/open-items.md); 0.9.1 made the check about five times faster, the rest stays listed there.
pymatgen's CifParser only parses and SpacegroupAnalyzer is spglib in C. On a 32-atom P1 cell (an fcc supercell with 1 536 operations) the kit took 361 ms against 13 ms, 28 times slower; on a four-atom cell they are level. The cause was the closure check, not the symmetry search (docs/parity.md, known limits); 0.9.1 made the check about five times faster, the rest stays listed there.
orientation_reduce: the kit reduces one matrix at a time (24 proper operators); orix reduces a vectorised batch
(Orientation.from_matrix + map_into_symmetry_reduced_zone). The kit is 2.5 to 12 times faster at these sizes.
ellipse_fit_1d: level with py4DSTEM's fit_ellipse_1D (0.94 and 1.1).
acom_match_scan: the kit's matchAll over the whole scan against py4DSTEM's match_single_pattern per pattern (one
core; Python's per-pattern time includes its own refinements, so this is a time, not a like-for-like algorithm). Per pattern the kit on one core is 14 times (8 x 8 scan) and 9 times (32 x 32) faster than py4DSTEM on one core, and on all cores 105 and 81 times.
| Function | Backend | Why / break-even |
|---|---|---|
niggli_reduce, reflections, kinematic_reflections, symmetry_detection, cif_import | CPU only | small arrays, branchy integer logic, readers; the kit is already faster than Python except where docs/open-items.md lists it |
orientation_reduce | CPU only | 24 small matrix products per rotation; the batch (100 000 in 0.2 s) is bound by memory traffic, a GPU would pay the transfer for no gain at these sizes |
ellipse_fit_1d | CPU only | one 1D least-squares fit per pattern; level with Python |
acom_library | CPU only | built once per phase (60 ms for 600 axes), not per pattern |
acom_match_scan | CPU all cores; Metal not above any measured N | Metal 0.294 ms per pattern at 64 patterns, 0.236 at 1 024, against 0.245 and 0.216 on all CPU cores: the break-even is not reached up to 1 024 patterns (the Metal path is 7 to 22 % slower); the 128 x 128 row (16 384 patterns) is not measured yet, and the Metal path stays an option (ACOMBackend.metal), not the default. A larger library (2 400 axes) is the other axis still to measure |
| Function | Backend | Why / break-even |
|---|---|---|
niggli_reduce, reflections, kinematic_reflections, symmetry_detection, cif_import | CPU only | small arrays, branchy integer logic, readers; the kit is already faster than Python except where docs/parity.md (known limits) lists it |
orientation_reduce | CPU only | 24 small matrix products per rotation; the batch (100 000 in 0.2 s) is bound by memory traffic, a GPU would pay the transfer for no gain at these sizes |
ellipse_fit_1d | CPU only | one 1D least-squares fit per pattern; level with Python |
acom_library | CPU only | built once per phase (60 ms for 600 axes), not per pattern |
acom_match_scan | CPU all cores; Metal not above any measured N | Metal 0.294 ms per pattern at 64 patterns, 0.236 at 1 024, against 0.245 and 0.216 on all CPU cores: the break-even is not reached up to 1 024 patterns (the Metal path is 7 to 22 % slower); the 128 x 128 row (16 384 patterns) is not measured yet, and the Metal path stays an option (ACOMBackend.metal), not the default. A larger library (2 400 axes) is the other axis still to measure |
Numbers in docs/parity.md are untouched by this table (time only).
| Kit | What it does | Reference | Version | Parity: present of rows | Docs |
|---|---|---|---|---|---|
| FormatoKit | File formats for electron microscopy: Velox EMD, DM3/DM4, HDF5/EMD, MRC, TIFF, MIB, EMPAD. | RosettaSciIO | 0.12.1 | 2 of 38 | API |
| ImagoKit | Image numerics: FFT, profiles, filters, alignment, measurement, segmentation. | NumPy, SciPy, scikit-image | 0.9.1 | 36 of 93 | API |
| DiffractoKit | Crystallography, diffraction geometry, ring and ellipse fits, indexing, orientation and ACOM. | pymatgen, py4DSTEM, orix | 0.11.0 | 22 of 148 | API |
| DiffractoKit | Crystallography, diffraction geometry, ring and ellipse fits, indexing, orientation and ACOM. | pymatgen, py4DSTEM, orix | 0.12.0 | 22 of 148 | API |
| SpectroKit | EDX quantification and EELS thickness, background and edges. | HyperSpy, exSpy | 0.13.2 | 58 of 100 | API |
| CuboKit | The 4D-STEM library: virtual imaging, centre of mass, DPC, strain, Bragg disks, parallax, ptychography. | py4DSTEM | 0.10.0 | 135 of 215 | API |
| SimulatoKit | Multislice TEM/STEM simulation: potentials, frozen phonons, scans, detectors, CTF. | abTEM | 0.5.0 | 38 of 129 | API |
| Package | Version | Date | Tag | Changes |
|---|---|---|---|---|
| FormatoKit | 0.12.1 | 2026-11-01 | tag | changelog |
| ImagoKit | 0.9.1 | 2026-11-01 | tag | changelog |
| DiffractoKit | 0.11.0 | 2026-10-30 | tag | changelog |
| DiffractoKit | 0.12.0 | 2026-11-01 | tag | changelog |
| SpectroKit | 0.13.2 | 2026-11-01 | tag | changelog |
| CuboKit | 0.10.0 | 2026-11-01 | tag | changelog |
| SimulatoKit | 0.5.0 | 2026-10-31 | tag | changelog |