Stored SSB fits carry a schema, and only the current one is read - 2026-10-11#
Historical: describes the code as of 2026-10-11; the
mean_phaseestimator is retired, and later schema versions replaced the one described. See the current fit methods.
Question#
A screening folder keeps each acquisition’s fitted SSB values in live/screen/<dataset>/config.json under
computed.ssb. Values stored before the package restructure reconstruct a different image with the current engine
(two real scans: inverted contrast on one, a lattice peak six times weaker on the other, while a fresh fit reproduces
the earlier pictures). Which stored fields changed meaning, and how does a reader tell a current fit from an earlier one?
Setup#
One synthetic scan, simulated in the probe script itself: a periodic weak phase object with positive phase at the
atom columns, 300 kV, 30 mrad, defocus -10 nm, 64 x 64 positions at 0.5 A, 128 x 128 detector at 0.6152 mrad per
pixel. The same array went through the engine before the restructure and through this tree, each with its own fresh
CuPy kernel cache, phase_estimator="mean_phase", 200 trials, seed 42, no 180-degree check. Scripts: scratch
probes/engine_compare.py (one tree), probes/engine_diff.py, probes/engine_cross.py.
Numbers#
Fixed values C10 -10 nm, C12 2 nm, phi12 0.4 rad:
session |
earlier engine loss |
this tree loss |
phases |
|---|---|---|---|
|
0.000520867 |
0.000520867 |
identical, bit for bit |
|
0.000984409 |
0.000984409 |
identical |
|
0.000892663 |
0.000892663 |
identical |
|
0.000982096 |
0.000982096 |
identical |
automatic detector sampling, rotation 0 |
0.000331408 |
0.000521682 |
correlation 0.17 |
this tree at |
0.000331408 |
identical to the earlier automatic output |
Fit with automatic detector sampling (truth C10 -10 nm):
engine |
bright-field radius used |
detector sampling |
fitted C10 |
C12 |
phi12 |
loss |
|---|---|---|---|---|---|---|
earlier |
49 px (integer half maximum) |
2 x 30 / 49 = 1.224 mrad per pixel |
-4.24 nm |
0.33 nm |
-1.21 rad |
0.000268 |
this tree |
48.69 px (disk edge) |
30 / 48.69 = 0.616 mrad per pixel |
-9.90 nm |
0.01 nm |
-0.14 rad |
0.000149 |
The earlier engine’s fitted values, reconstructed by this tree with automatic sampling: loss 0.000974, correlation 0.13 with the picture the earlier engine made from the same values. This tree’s own fit: correlation 0.86 with it.
What changed, by stored field#
stored field |
earlier engine |
this tree |
carries over |
|---|---|---|---|
|
angle below 180 plus the flag, physical angle = angle + 180 x flag |
the same |
the convention does; a |
|
chi sign, units and angle reference as now; fitted with detector sampling 2 x semiangle / half-maximum radius |
fitted with semiangle / disk-edge radius |
no: C10 came out at 0.4 to 0.5 of the current value |
|
Angstrom stored under an nm name (before 2026-09-24) |
nm |
no |
|
physical angle up to 360, no flag |
below 180 plus flag |
the angle does, read as physical |
|
phase variance with zero aperture weight beyond half the disk; a session that had not fitted reported the batched evaluator |
exact reconstruction loss |
no, another quantity |
|
bright-field selection radius in pixels |
the same |
yes |
|
acquisition settings |
the same |
yes |
So the engine’s conventions did not change; the automatic detector calibration did
(record), and every stored fit was made without an explicit det_sampling.
Decision#
persistence.SCHEMA is 6 and persistence.FIT_SCHEMA = "quantem.ssb-fit/6" is derived from it. write_fit_metadata
writes "schema": FIT_SCHEMA into computed.ssb; series.stored_fit(config) returns a block only when it carries
that string, and saved_fit and acquisition_settings read through it. A saved fit record counts only at schema 6.
Any other stored fit is absent: nothing in it is read, a probe reference is fitted again, and write_fit_metadata
replaces such a block whole. The key and the value form follow the .qem scientific-metadata schema string
("schema": "quantem.scientific-metadata/2"), whose readers also refuse another version instead of reinterpreting it.
Schema 5 could not serve unchanged: fit records of schema 5 exist that were written with the earlier sampling
("det_sampling": 1.0909 = 2 x 30 / 55 in their signature), so 5 does not prove the current convention.
Rejected#
Converting earlier values (C10 x 2, or dividing unmarked Angstrom by 10): the ratio is not a constant, it depends on the disk radius and on which twin of the 180-degree ambiguity the earlier fit took.
Accepting a block that declares
aberration_unit: "nm": 76 of 687 surveyed blocks declare it and every one of them was fitted with the earlier sampling.A separate marker number beside
SCHEMA: two numbers for one contract can disagree.Reading the acquisition settings (voltage, semiangle, scan step) of an earlier block while ignoring its fit: one block would then be half trusted, and the settings are also in
dataset.yamlor the call.