Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions probeflow/core/metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,11 @@ def metadata_from_createc_dat_report(report) -> ScanMetadata:
from probeflow.io.createc_interpretation import createc_dat_experiment_metadata
experiment_metadata = createc_dat_experiment_metadata(hdr)

lx_a = _f(hdr.get("Length x[A]", "0"), 0.0)
ly_a = _f(hdr.get("Length y[A]", "0"), 0.0)
scan_range = (lx_a * 1e-10, ly_a * 1e-10)
from probeflow.io.readers.createc_dat import decoded_scan_range_m

# Extent of the decoded planes, consistent with ``shape`` below — pairing
# the full programmed frame with the decoded shape skews pixel sizes.
scan_range = decoded_scan_range_m(report)

return ScanMetadata(
path=Path(report.path),
Expand Down
5 changes: 3 additions & 2 deletions probeflow/io/converters/createc_dat_to_npy.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from probeflow.io.readers.createc_scan import (
createc_public_planes_from_report,
)
from probeflow.io.readers.createc_dat import scan_range_m_from_header
from probeflow.io.readers.createc_dat import decoded_scan_range_m
from probeflow.provenance.export import write_provenance_sidecars

log = logging.getLogger(__name__)
Expand Down Expand Up @@ -228,7 +228,8 @@ def build_createc_dat_npy_bundle(
bundle_name=bundle_dir.name,
raw_definition=_basis_note(basis),
scan_pixels=(int(report.decoded_Nx), int(report.decoded_Ny)),
scan_range_m=scan_range_m_from_header(report.header),
# Matches scan_pixels: the decoded planes' extent, not the programmed frame.
scan_range_m=decoded_scan_range_m(report),
original_shape=(int(report.original_Nx), int(report.original_Ny)),
decoded_shape=(int(report.decoded_Nx), int(report.decoded_Ny)),
detected_channel_count=int(report.detected_channel_count),
Expand Down
27 changes: 26 additions & 1 deletion probeflow/io/readers/createc_dat.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,13 +222,38 @@ def scale_channels_for_scan(report: CreatecDatDecodeReport) -> list[np.ndarray]:


def scan_range_m_from_header(hdr: dict[str, str]) -> tuple[float, float]:
"""Return Createc lateral scan range in metres."""
"""Return the *programmed acquisition frame* in metres.

``Length x/y[A]`` describe the frame the controller scanned:
``original_Nx`` × ``original_Ny`` pixels. The decoded planes ProbeFlow
exposes are smaller (first column removed; partial scans row-trimmed), so
callers pairing a physical range with decoded arrays must use
:func:`decoded_scan_range_m` instead.
"""

lx_a = _f(hdr.get("Length x[A]", "0"), 0.0)
ly_a = _f(hdr.get("Length y[A]", "0"), 0.0)
return (lx_a * 1e-10, ly_a * 1e-10)


def decoded_scan_range_m(report: CreatecDatDecodeReport) -> tuple[float, float]:
"""Physical extent of the decoded planes in metres.

The per-pixel step is fixed by the acquisition grid
(``Length / original_N``; independently confirmed by the header's own
``Delta X [Dac] * Dacto[A]xy`` calibration), so the decoded extent is that
step times the decoded pixel count. Using the full-frame lengths with the
decoded shape would overestimate the x pixel size by ``Nx/(Nx-1)`` on every
scan (and the y pixel size by ``Ny/trimmed_Ny`` on partial scans) in every
downstream measurement, FFT axis, and lattice vector.
"""

full_x_m, full_y_m = scan_range_m_from_header(report.original_header)
px_x_m = full_x_m / report.original_Nx if report.original_Nx > 0 else 0.0
px_y_m = full_y_m / report.original_Ny if report.original_Ny > 0 else 0.0
return (px_x_m * report.decoded_Nx, px_y_m * report.decoded_Ny)


def _split_createc_dat_payload(path: Path, raw: bytes) -> tuple[bytes, bytes]:
"""Return ``(header_bytes, decompressed_payload)`` for a Createc image.

Expand Down
6 changes: 4 additions & 2 deletions probeflow/io/readers/createc_scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
has_legacy_stm_two_channel_layout,
read_createc_dat_report,
scale_channels_for_scan,
scan_range_m_from_header,
decoded_scan_range_m,
)
from probeflow.core.scan_model import Scan

Expand Down Expand Up @@ -269,7 +269,9 @@ def _as_f64(arr: np.ndarray) -> np.ndarray:
plane_units=plane_units,
plane_synthetic=synthetic,
header=hdr,
scan_range_m=scan_range_m_from_header(hdr),
# Extent of the decoded planes (first column removed, partial rows
# trimmed), not the programmed frame — keeps pixel sizes physical.
scan_range_m=decoded_scan_range_m(report),
source_path=path,
source_format="dat",
experiment_metadata=createc_dat_experiment_metadata(hdr),
Expand Down
32 changes: 16 additions & 16 deletions test_data/output_raw_npy/npy/A250320.probeflow.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
{
"artifact_type": "createc_dat_npy_bundle",
"source_path": "C:\\Users\\rnpla\\Desktop\\stm\\ProbeFlow\\test_data\\sample_input\\A250320.191933.dat",
"source_path": "/Users/peterjacobson/ProbeFlow/test_data/sample_input/A250320.191933.dat",
"source_format": "dat",
"basis": "raw",
"bundle_dir": "C:\\Users\\rnpla\\Desktop\\stm\\ProbeFlow\\test_data\\output_raw_npy\\npy\\A250320.191933_raw_npy",
"bundle_name": "A250320.191933_raw_npy",
"raw_definition": "RAW means decoded Createc numerical arrays after ProbeFlow's parser cleanup, before physical scaling or PNG normalization. It is not a byte-exact copy of the compressed file payload.",
"basis": "physical",
"bundle_dir": "test_data/output_raw_npy/npy/A250320.191933_physical_npy",
"bundle_name": "A250320.191933_physical_npy",
"raw_definition": "Physical arrays are converted with ProbeFlow's Createc calibration logic and match the public Scan representation.",
"scan_pixels": [
511,
60
],
"scan_range_m": [
2.0020142000000002e-07,
2.0020142000000002e-07
1.9981040160156252e-07,
2.3461103906250004e-08
],
"original_shape": [
512,
Expand All @@ -35,15 +35,15 @@
"file_name": "A250320.191933_1.npy",
"public_name": "Z forward",
"public_unit": "m",
"saved_unit": "DAC",
"saved_unit": "m",
"source_native_index": 0,
"source_name": "Z forward",
"source_unit": "m",
"semantic": "z",
"direction": "forward",
"synthetic": false,
"scale_factor": 3.8000000000000005e-13,
"dtype": "float32",
"dtype": "float64",
"shape": [
60,
511
Expand All @@ -54,15 +54,15 @@
"file_name": "A250320.191933_2.npy",
"public_name": "Z backward",
"public_unit": "m",
"saved_unit": "DAC",
"saved_unit": "m",
"source_native_index": 0,
"source_name": "Z forward",
"source_unit": "m",
"semantic": "z",
"direction": "backward",
"synthetic": true,
"scale_factor": 3.8000000000000005e-13,
"dtype": "float32",
"dtype": "float64",
"shape": [
60,
511
Expand All @@ -73,15 +73,15 @@
"file_name": "A250320.191933_3.npy",
"public_name": "Current forward",
"public_unit": "A",
"saved_unit": "DAC",
"saved_unit": "A",
"source_native_index": 1,
"source_name": "Current forward",
"source_unit": "A",
"semantic": "current",
"direction": "forward",
"synthetic": false,
"scale_factor": -9.5367431640625e-15,
"dtype": "float32",
"dtype": "float64",
"shape": [
60,
511
Expand All @@ -92,15 +92,15 @@
"file_name": "A250320.191933_4.npy",
"public_name": "Current backward",
"public_unit": "A",
"saved_unit": "DAC",
"saved_unit": "A",
"source_native_index": 1,
"source_name": "Current forward",
"source_unit": "A",
"semantic": "current",
"direction": "backward",
"synthetic": true,
"scale_factor": -9.5367431640625e-15,
"dtype": "float32",
"dtype": "float64",
"shape": [
60,
511
Expand Down Expand Up @@ -635,6 +635,6 @@
"PSTMAFM.EXE_Date": "07/10/2022 07:44:44 DSP-COMPDATE= Mar 6 2022 12:44:26",
"memo:0": ""
},
"export_path": "C:\\Users\\rnpla\\Desktop\\stm\\ProbeFlow\\test_data\\output_raw_npy\\npy\\A250320.191933_raw_npy",
"export_path": "test_data/output_raw_npy/npy/A250320.191933_physical_npy",
"export_format": "npy"
}
30 changes: 15 additions & 15 deletions test_data/output_raw_npy/npy/A250320.provenance.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
{
"artifact_type": "createc_dat_npy_bundle",
"source_path": "C:\\Users\\rnpla\\Desktop\\stm\\ProbeFlow\\test_data\\sample_input\\A250320.191933.dat",
"source_path": "/Users/peterjacobson/ProbeFlow/test_data/sample_input/A250320.191933.dat",
"source_format": "dat",
"basis": "raw",
"bundle_dir": "C:\\Users\\rnpla\\Desktop\\stm\\ProbeFlow\\test_data\\output_raw_npy\\npy\\A250320.191933_raw_npy",
"bundle_name": "A250320.191933_raw_npy",
"raw_definition": "RAW means decoded Createc numerical arrays after ProbeFlow's parser cleanup, before physical scaling or PNG normalization. It is not a byte-exact copy of the compressed file payload.",
"basis": "physical",
"bundle_dir": "test_data/output_raw_npy/npy/A250320.191933_physical_npy",
"bundle_name": "A250320.191933_physical_npy",
"raw_definition": "Physical arrays are converted with ProbeFlow's Createc calibration logic and match the public Scan representation.",
"scan_pixels": [
511,
60
],
"scan_range_m": [
2.0020142000000002e-07,
2.0020142000000002e-07
1.9981040160156252e-07,
2.3461103906250004e-08
],
"original_shape": [
512,
Expand All @@ -35,15 +35,15 @@
"file_name": "A250320.191933_1.npy",
"public_name": "Z forward",
"public_unit": "m",
"saved_unit": "DAC",
"saved_unit": "m",
"source_native_index": 0,
"source_name": "Z forward",
"source_unit": "m",
"semantic": "z",
"direction": "forward",
"synthetic": false,
"scale_factor": 3.8000000000000005e-13,
"dtype": "float32",
"dtype": "float64",
"shape": [
60,
511
Expand All @@ -54,15 +54,15 @@
"file_name": "A250320.191933_2.npy",
"public_name": "Z backward",
"public_unit": "m",
"saved_unit": "DAC",
"saved_unit": "m",
"source_native_index": 0,
"source_name": "Z forward",
"source_unit": "m",
"semantic": "z",
"direction": "backward",
"synthetic": true,
"scale_factor": 3.8000000000000005e-13,
"dtype": "float32",
"dtype": "float64",
"shape": [
60,
511
Expand All @@ -73,15 +73,15 @@
"file_name": "A250320.191933_3.npy",
"public_name": "Current forward",
"public_unit": "A",
"saved_unit": "DAC",
"saved_unit": "A",
"source_native_index": 1,
"source_name": "Current forward",
"source_unit": "A",
"semantic": "current",
"direction": "forward",
"synthetic": false,
"scale_factor": -9.5367431640625e-15,
"dtype": "float32",
"dtype": "float64",
"shape": [
60,
511
Expand All @@ -92,15 +92,15 @@
"file_name": "A250320.191933_4.npy",
"public_name": "Current backward",
"public_unit": "A",
"saved_unit": "DAC",
"saved_unit": "A",
"source_native_index": 1,
"source_name": "Current forward",
"source_unit": "A",
"semantic": "current",
"direction": "backward",
"synthetic": true,
"scale_factor": -9.5367431640625e-15,
"dtype": "float32",
"dtype": "float64",
"shape": [
60,
511
Expand Down
Loading
Loading