Skip to content

ENH: Reconcile PET timing and decay correction when combining runs#326

Merged
mnoergaard merged 15 commits into
mainfrom
fix_combine_runs_time
Jul 16, 2026
Merged

ENH: Reconcile PET timing and decay correction when combining runs#326
mnoergaard merged 15 commits into
mainfrom
fix_combine_runs_time

Conversation

@mnoergaard

Copy link
Copy Markdown
Collaborator

Summary

This PR addresses issue #325 by improving PETPreps --combine-runs workflow handling for PET datasets where multiple runs belong to the same tracer injection but later runs use their own TimeZero.

Previously, PETPrep treated runs whose FrameTimesStart began at 0 as contiguous with the previous run, which could incorrectly remove real gaps between acquisitions. The combine step now uses BIDS PET timing metadata to place all runs onto the first run’s timing reference.

Changes

  • Align combined FrameTimesStart using TimeZero, falling back to InjectionStart when needed.
  • Shift FrameReferenceTime and merge frame-wise metadata across runs.
  • Preserve the previous cumulative-duration behavior as a fallback when timing metadata are insufficient.
  • Rescale decay-corrected images to the first run’s ImageDecayCorrectionTime when runs were corrected to different reference times and RadionuclideHalfLife is available.
  • Add regression tests for delayed second-run timing and decay-correction rescaling.
  • Document the updated --combine-runs timing behavior.

@codecov

codecov Bot commented Jun 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.36575% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.05%. Comparing base (e1d85ca) to head (66541e0).

Files with missing lines Patch % Lines
petprep/utils/bids.py 98.79% 1 Missing and 2 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #326      +/-   ##
==========================================
+ Coverage   86.43%   87.05%   +0.62%     
==========================================
  Files          89       89              
  Lines       10077    10525     +448     
  Branches     1060     1129      +69     
==========================================
+ Hits         8710     9163     +453     
+ Misses       1134     1133       -1     
+ Partials      233      229       -4     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@mnoergaard

Copy link
Copy Markdown
Collaborator Author

@mathesong and @bendhouseart - any feedback to this? Otherwise, I will go ahead and merge it, and then we can update it, if any issues appear.

@mnoergaard

Copy link
Copy Markdown
Collaborator Author

A few review points at this stage:

[P1] Incompatible decay correction silently falls through to concatenation.
bids.py (line 396) returns unity factors whenever metadata are incomplete, corrected/uncorrected runs are mixed, half-lives disagree, or the radionuclide is unsupported. The images are still combined, and bids.py (line 437) merely removes the decay metadata. Removing metadata does not make incompatible voxel values compatible.
This also affects valid PET-BIDS radionuclides other than C-11/F-18. For O-15 runs corrected to time zeros 600 seconds apart, the code applies 1.0; the required conversion factor is approximately 30.03. RadionuclideHalfLife is not a standard PET-BIDS field, so its presence cannot generally be assumed. The behavior is explicitly documented at usage.rst (line 89), but it should instead fail closed.

[P1] Heuristic “contiguous run” offsets are treated as exact decay timing.
When timing cannot be reconciled, bids.py (line 319)substitutes the end of the preceding run. That inferred value is then passed directly into decay rescaling at bids.py (line 568).
For two 600-second F-18 runs separated by a real 7200-second gap, missing timing metadata make the code apply 1.065; the correct factor is 2.133. It then reports the combined series as decay-corrected to a common time. Timing offsets need provenance, and fallback offsets must never drive quantitative rescaling.

[P2] TimeZero and InjectionStart are not checked for consistency.
bids.py (line 312) always prefers a usable wall-clock TimeZero difference and only consults InjectionStart when that fails. For the same injection, both calculations should agree. Disagreement can indicate separate injections, a date rollover, or bad metadata. Currently those cases may be combined silently. Multi-day scans can also be shifted by the wrong number of days because only time-of-day is considered.

@mnoergaard
mnoergaard merged commit e8d719a into main Jul 16, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant