Skip to content

Filter MNI-registered brains out of longitudinal template discovery#308

Merged
nx10 merged 1 commit into
mainfrom
fix/longitudinal-template-discovery-space
Apr 14, 2026
Merged

Filter MNI-registered brains out of longitudinal template discovery#308
nx10 merged 1 commit into
mainfrom
fix/longitudinal-template-discovery-space

Conversation

@nx10
Copy link
Copy Markdown
Contributor

@nx10 nx10 commented Apr 14, 2026

Summary

rbc.bids.longitudinal.template.discover_template_inputs was filtering on desc == "brain" + suffix == "T1w" but not on space. Cross-sectional anat writes both a native-space and an MNI-registered desc-brain T1w per session, so on a real two-session derivatives tree it returned 4 inputs for 2 sessions with duplicate LTA filenames, breaking the mri_robust_template call.

Fix is one filter clause: pl.col("space").is_null(). Adds a regression unit test that includes the MNI-registered row.

Context

Test plan

  • uv run pytest tests/unit/bids/test_longitudinal_template.py -v — 6 passed including the new test_excludes_mni_registered_brains.
  • uv run ruff check / format --check / mypy clean.
  • Nightly test_full after Add ds000114 fixture infrastructure for longitudinal tests #307 rebases will exercise the real two-session path on ds000114.

discover_template_inputs picked up both the native-space and the
MNI-registered desc-brain T1w that cross-sectional anat writes per
session, doubling the inputs and producing duplicate LTA filenames in
the mri_robust_template invocation. Latent because existing unit tests
fed only native-space rows. Surfaced by the ds000114 fixture infra in
PR #307. Adds an explicit regression test covering the MNI variant.
@github-actions
Copy link
Copy Markdown

Coverage

Coverage Report
FileStmtsMissCoverMissing
rbc
   __init__.py10100% 
   context.py25196%77
   metadata.py670100% 
rbc/bids
   __init__.py90100% 
   _schema.py585499%776, 782, 790, 1101
   anatomical.py24387%44, 47–48
   builder.py72790%233–235, 362, 364–365, 386
   functional.py42588%46–49, 84
   metrics.py23195%44
   qc.py170100% 
   query.py674237%103–107, 121–125, 127–128, 130–135, 137, 139, 153, 159–165, 198, 207, 209–216, 225, 257, 266–267
   session.py470100% 
rbc/bids/longitudinal
   __init__.py00100% 
   anatomical.py170100% 
   functional.py110100% 
   template.py270100% 
rbc/cli
   __init__.py10100% 
   all.py49295%84, 109
   anatomical.py25292%47, 63
   base.py71987%56, 62, 123–125, 131–133, 156
   functional.py33293%67, 87
   main.py420100% 
   metrics.py42295%77, 95
   qc.py25292%45, 61
rbc/cli/longitudinal
   __init__.py80100% 
   process.py27292%52, 69
   template.py230100% 
rbc/core
   __init__.py30100% 
   common.py261253%43–45, 62–70
   fileops.py27485%69–72
   fsl2itk.py420100% 
   nifti.py192597%236–237, 244–245, 524
   niwrap.py711381%59, 143–144, 146–148, 150–151, 156–157, 159, 161–162
rbc/core/anatomical
   __init__.py40100% 
   registration.py15473%59, 151, 166, 183
   segmentation.py24866%64, 74–76, 92, 114, 125, 141
rbc/core/functional
   __init__.py130100% 
   coregistration.py7271%44, 55
   despiking.py7357%32, 36–37
   distortion.py1304069%269–271, 321, 324, 332–335, 341–346, 349, 352–353, 356, 365–369, 375–376, 387–388, 391, 397, 443–444, 447, 455, 461, 470–471, 474, 484, 491
   erosion.py32196%50
   initialization.py9455%35, 42–43, 63
   masking.py342526%53, 55–56, 58–59, 62–65, 69, 91, 134, 183, 197, 208, 223, 233, 249, 258, 271, 285, 296, 306, 319, 328
   motion.py573735%62, 64–67, 69, 71, 73, 76–77, 83–84, 86–87, 95–97, 99, 102, 105, 107, 124–125, 135–138, 159, 169, 171–172, 175, 177–179, 181, 183
   nuisance.py816025%78, 80–85, 87, 89–90, 93, 96–98, 100–102, 104–110, 112–116, 118, 163, 165, 167, 170–171, 173–175, 178, 181–182, 185–187, 190–193, 197, 203–205, 207, 235, 243, 269, 278, 307, 316, 322
   regressors.py89693%163, 193, 325–328
   resampling.py544320%37–42, 74–76, 78, 80–81, 85–87, 90, 93, 105, 107–108, 112, 114, 150–152, 154–155, 159, 161–162, 167–169, 173–174, 177, 180, 187, 199, 201–202, 207, 209
   timing.py161131%46–47, 49–53, 58, 60, 66–67
rbc/core/longitudinal
   __init__.py10100% 
   freesurfer.py350100% 
   transform.py46784%106–107, 165–168, 170
rbc/core/metrics
   __init__.py30100% 
   alff.py90198%265
   reho.py660100% 
   smoothing.py7357%36, 42–43
   standardization.py271159%64, 66–68, 70, 72–75, 77–78
   timeseries.py70198%147
rbc/core/qc
   __init__.py60100% 
   dvars.py260100% 
   motion.py310100% 
   registration.py410100% 
   xcp.py410100% 
rbc/orchestration
   __init__.py32293%90, 93
   all.py41978%131–132, 137, 145, 153–154, 171, 173–174
   anatomical.py372240%49–52, 57–58, 60–63, 85–87, 89–90, 94, 101, 104, 109–110, 116, 118
   functional.py411270%124–126, 128–129, 133, 139, 142, 147–148, 157, 159
   metrics.py463034%32–35, 38–40, 67, 75–76, 100–102, 104–106, 110, 118–121, 123–124, 130–132, 137, 145, 152, 154
   qc.py340100% 
rbc/orchestration/longitudinal
   __init__.py38197%78
   anatomical.py160100% 
   functional.py140100% 
   template.py51590%48, 53–55, 101
rbc/workflows
   __init__.py100100% 
   anatomical.py291162%88–91, 95–100, 105
   functional.py925738%108–109, 117, 122–123, 131, 202–203, 206–207, 210–211, 214, 217–220, 230–232, 242–243, 246, 249, 252–254, 260, 263, 267–268, 275–276, 283–284, 291–292, 295–297, 300–303, 315–316, 328, 330–333, 336–337, 346–347, 355, 362
   metrics.py411856%80, 83–84, 93–94, 99–102, 105–108, 112–115, 119
   qc.py553438%88–89, 92–93, 96, 99, 102–107, 110, 119–121, 125–128, 130–134, 136–137, 139–141, 144, 161, 167, 169
rbc/workflows/longitudinal
   __init__.py00100% 
   anatomical.py24866%80–83, 85–87, 91
   functional.py11281%66, 72
   template.py15566%54–55, 59–60, 68
rbc_resources
   __init__.py380100% 
TOTAL346860182% 

Tests Skipped Failures Errors Time
758 0 💤 0 ❌ 0 🔥 10.538s ⏱️

@nx10 nx10 merged commit e8a89f4 into main Apr 14, 2026
8 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