DICOM coordinate validation#
This is the validation record for #2066: independent test methods, fixture provenance, reproducible checks and known limitations. For the coordinate definition, affected historical calculations, physical tolerances and plotting guidance, read DICOM coordinates and gamma, illustrated. That notebook is the physicist-facing explanation; those examples are not repeated here.
Unless a row states otherwise, the one-off checks below compared the original
implementation at 400b61fe8 with this implementation at 658c4b6f0. The
limitations section lists the DICOM helpers and gamma search cases that these
checks do not cover.
Independence of the checks#
The reference geometry comes from DICOM PS3.3 C.7.6.2.1.1 and C.8.8.3.2, not the production conversion. The checks use both a matrix oracle and a separately tabulated storage encoding, with manually worked voxels to check the oracle itself. Asymmetric nonzero dose values expose incorrect reversals and row/column swaps that equal-shaped or uniform arrays could hide.
The physical grid-equality check is tested against exhaustive voxel positions, including rounded direction cosines, both acceptance boundaries and errors on interior slices. Its compact implementation checks four corners of every slice: displacement is affine in row and column, so its convex Euclidean norm reaches a maximum at an in-plane corner. It retains the original encoded cosines; the cardinal approximation used for separable axis extraction is not substituted into this comparison. The notebook explains the user-facing geometric limits and their distinction from clinical significance.
Evidence and its limits#
Validation combines ongoing local tests with recorded historical checks:
A homogeneous 4x4 matrix implementation in the synthetic fixture, checked against manually worked HFP and FFDL voxels.
A manually tabulated storage encoding in the orientation invariance tests. This starts with known patient axes and dose values and does not call the production geometry code or the matrix oracle to encode them.
The historical real-file orientation metadata and
expected_fixed_xyz.jsonbaseline, verified before retiring the download-backed tests as recorded below.
One-off independent checks:
Check |
Result |
|---|---|
Eight orientations, increasing and decreasing relative slice offsets |
All 16 encodings recover exactly the original physical axes and dose |
All 64 reference/evaluation orientation pairs, both interpolators |
Same results as gamma on the known physical grid, within |
Identical and discrepant dose fields for every pair |
Identical fields give zero; the discrepancy includes failing points and remains orientation invariant |
First/last crop on each of three patient axes in all eight orientations |
All 48 cropped-reference comparisons give zero gamma against their full grid |
Off-grid dose interpolation in all eight orientations |
Agrees with independently averaged voxel corners within |
Historical metadata files for all eight orientations |
Zero difference from the independent DICOM matrix calculation |
Historical IEC FIXED baseline and pre-PR implementation |
Exactly equal in all eight orientations |
800 additional seeded random grids, including unequal spacing and uneven/decreasing slice offsets |
Zero coordinate difference from the matrix calculation; every dose value retains its physical voxel |
800 seeded perturbed grid pairs |
The 0.01 mm equality decision at |
IEC FIXED on those 800 grids |
Exactly equal to the original implementation |
Negative control using the original dose conversion |
New physical-grid tests detect all 15 changed encoding cases; ordinary HFS with increasing offsets passes |
The randomised probes used seed 2066, 100 grids per orientation, dimensions between 2 and 8, origins within +/-1500 mm, and spacings between 0.2 and 5 mm. The committed seeded matrix regression also checks 100 grids per orientation. These checks are not a statistical estimate of clinical error frequency.
The historical orientation DICOM files have empty pixel data. They verify
real metadata and the IEC convention, not nonzero real dose registration.
The dose-order and gamma checks deliberately use asymmetric, nonzero
synthetic dose data. The downloaded archive matched the repository’s SHA-1
e09f71ebf4d98a58bc3c00e7dd9f59e91e9f8bb6.
Retirement of downloaded test fixtures#
On 26 September 2026 the original tests were rerun before removing their download dependency. The replay used Python 3.12.14, NumPy 1.26.4, pydicom 3.0.2 and pytest 9.1.1, with the existing cached downloads. These are results from the named revisions, not a claim that the old DICOM expectations pass against the corrected implementation.
Revision and test selection |
Result |
|---|---|
Original code at |
7 passed, 1 skipped |
PR at |
14 passed |
The original IEC PATIENT test was already unconditionally skipped because its assertions failed; it was not a passing validation. The original DICOM coordinate JSON matched the original implementation in all eight orientations. On the PR, that JSON agrees only for HFS: the other orientations were deliberately checked against the independent DICOM matrix instead. The IEC FIXED JSON, wedge dose baseline, non-square-pixel contour test and patient-position checks passed without changing their expectations.
The precise original tests remain available in Git history: original coordinate tests, original dose tests, and PR coordinate tests before removal. To replay either historical run in a checkout of that revision, use:
uv run -- python -m pytest -q \
lib/pymedphys/tests/dicom/test_coords.py \
lib/pymedphys/tests/dicom/test_dose.py -ra
Fixture provenance is retained for that optional replay:
Fixture |
Source |
Repository SHA-1 |
|---|---|---|
|
|
|
|
|
|
|
|
The roughly 75 MiB dose archive and separate DICOM files are no longer downloaded by these coordinate and dose tests. Their useful coverage is retained locally:
Retired downloaded check |
Ongoing local coverage |
|---|---|
DICOM axes for eight orientations |
Analytic matrix tests, manually encoded physical grids, and seeded voxel checks |
IEC FIXED historical JSON |
Independent image-axis projection tests for all eight orientations, with the exact historical agreement recorded above |
Non-square-pixel dose/contour example |
Unequal row/column spacing in voxel-placement and interpolation tests, plus the local structure-mask regression |
Wedge dose values, units and coordinates |
A generated asymmetric HFS dose written and read locally in implicit and explicit VR little endian; expected dose values and coordinates are defined independently |
Patient-position checks using orientation and structure files |
Generated datasets covering all eight orientations, with and without Patient Position, missing Image Orientation (Patient), and a conflicting Patient Position |
This removes recurring vendor-file regression coverage from this test group; the recorded historical pass is evidence for those revisions, not a substitute for future testing. Local DICOM serialisation retains file-reading coverage, but it cannot represent every vendor-specific encoding. Other repository test groups may still download their own data. The fixture URL/hash registry is retained so historical tests can be replayed.
Remaining limitations#
Oblique geometry is outside the three-independent-patient-axes contract. The private IEC PATIENT option of
xyz_axes_from_datasetraisesNotImplementedError.When this record was written, gamma could miss singleton evaluation planes (#2070) and evaluation grids narrower than one search step, and four strict expected-failure tests recorded this. Both have since been fixed: #2119 gives every analysed reference point a value, and #2126 searches singleton evaluation axes directly. Those four tests now pass as ordinary tests.
Reproducing the committed checks#
After the usual locked development installation, run from the repository root:
uv run -- python -m pytest -q \
lib/pymedphys/tests/dicom/test_coords.py \
lib/pymedphys/tests/dicom/test_coords_analytic.py \
lib/pymedphys/tests/dicom/test_orientation_invariance.py \
lib/pymedphys/tests/dicom/test_dose.py \
lib/pymedphys/tests/dicom/structure/test_masking.py \
lib/pymedphys/tests/gamma/test_gamma_axes.py \
lib/pymedphys/tests/gamma/test_gamma_shell.py \
lib/pymedphys/tests/interp/test_interp.py
The selection uses only generated local fixtures, needs no network access or downloaded data, and writes generated DICOM files only to pytest’s temporary directories. The four historical gamma-search expected failures above now run as ordinary passing regression tests.
get_dose_grid_structure_mask and DicomDose.coords follow the pixel
array’s (slice, row, column) order in every supported orientation. Their
tests cover all eight orientations, both slice orders, and square and
rectangular grids, and check that find_dose_within_structure selects the
same dose in every orientation. With the previous helpers, which treated rows
as y and columns as x, exactly the 32 decubitus cases fail.
Gamma performance is a separate experiment; see the workstation study and upload instructions and the recorded fixed-grid demonstration.