Data model and coordinates#
A 4D-STEM acquisition records one two-dimensional diffraction pattern at each two-dimensional probe position:
The public array convention is
Therefore \(\mathbf R=(R_r,R_c)\) is the probe/scan coordinate in real space
and \(\mathbf k=(k_r,k_c)\) is the detector scattering coordinate in
diffraction space.
Code uses row/column; equations use the matching \(r\)/\(c\) component
subscripts. Both express the same ordered axes.
Shapes and indexing#
For a source with scan shape \((N_{R_r},N_{R_c})\) and detector shape \((N_{k_r},N_{k_c})\):
data.shape == (scan_rows, scan_columns, detector_rows, detector_columns)
== (N_{R_r}, N_{R_c}, N_{k_r}, N_{k_c})
data[row, column] selects one diffraction pattern. A scan-shaped result such
as BF or iDPC has shape (scan_rows, scan_columns). A detector-shaped result
such as the mean diffraction pattern has shape
(detector_rows, detector_columns).
Python acquisition and calibration#
io.load(path) returns Dataset4dstemGPU, an acquisition handle for encoded
GPU storage. It is independent of QuantEM’s core dataset classes. Use ordinary
indexing to decode the selected working region into a Torch tensor:
pattern = data[10, 12]
patch = data[8:12, 10:16, 64:128, 64:128]
Attribute |
Meaning |
|---|---|
|
Logical dimensions and number of values |
|
Per-axis spacing |
|
Unit for each axis |
|
First-pixel coordinate for each axis |
|
Complete calibration, provenance and storage record |
Sampling, units and origin are read-only tuples in the same axis order as
shape. Unknown entries are None. A selected Torch tensor does not retain
these axis records automatically. When displaying a crop, use its matching
sampling and account for the crop offset; do not label it with invented units.
See I/O for selection and lifetime rules.
Regions are half-open#
Both scan and detector regions use:
(row_start, row_stop, column_start, column_stop)
This is a half-open interval: the start is included and the stop is excluded. Cropping is an explicit scientific choice, never an implicit memory or speed policy.
Binning preserves counts#
For detector bin factors \((b_r,b_c)\), the binned count at output detector coordinate \((Q_r,Q_c)\) is
The implementation widens the accumulator before summation. Incomplete edge bins are retained, so output dimensions use ceiling division. The output metadata records the original and output shapes, factors, source dtype, accumulation dtype, and output dtype.
Units#
Quantity |
Coordinates |
Typical units |
|---|---|---|
Probe/scan position \(\mathbf R\) |
\((R_r,R_c)\) |
scan pixels, nm, or Å |
Detector position \(\mathbf k\) |
\((k_r,k_c)\) |
detector pixels, mrad, or reciprocal length |
Detector mask \(M(\mathbf k)\) |
\((k_r,k_c)\) |
dimensionless weight |
Detector signal \(I(\mathbf R,\mathbf k)\) |
all four axes |
detector counts |
Never label an uncalibrated detector pixel as mrad or a scan index as physical length. Calibration origin and units are part of provenance.
Implementation invariant#
CUDA thread indices, Metal grid coordinates, and WebGPU invocation IDs may be
laid out for coalescing. The adapter must translate that private layout back to
the public (row, column) ≡ (r, c) contract. Transposition, flattening, or
detector-major storage is an implementation detail and requires parity tests
that catch row/column swaps and rectangular-shape mistakes.