Skip to content

Commit 318ae42

Browse files
committed
Refactor to resample template per task
Templates for different takss _could_ be different resolutions. This refactors the resampling such that a template is generated per task for the longitudinal workflow.
1 parent ee0da2a commit 318ae42

5 files changed

Lines changed: 31 additions & 22 deletions

File tree

src/rbc/bids/longitudinal/functional.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,9 @@ def resolve_longitudinal_func(
5050
without=["space"],
5151
)
5252

53+
task = func_df["task"].unique()[0]
5354
return {
54-
"template": tpl_q.expect(tpl_df, res="bold", suffix="T1w"),
55+
"template": tpl_q.expect(tpl_df, suffix="T1w", res=task),
5556
"anat_to_template_xfm": tpl_q.expect(
5657
tpl_df,
5758
suffix="xfm",

src/rbc/bids/longitudinal/template.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ class TemplateInputs(NamedTuple):
2121
sub: Subject label.
2222
sessions: Per-input session labels (parallel to ``files``).
2323
files: Per-session preprocessed T1w brain volumes.
24-
bold_ref: First BOLD volume for grid reference.
24+
bold_ref: Per-session preprocessed BOLD volumes (all tasks).
2525
"""
2626

2727
sub: str
2828
sessions: list[str]
2929
files: list[Path]
30-
bold_ref: Path | None
30+
bold_files: dict[str, Path]
3131

3232

3333
def discover_template_inputs(
@@ -58,17 +58,13 @@ def discover_template_inputs(
5858
# the mri_robust_template invocation.
5959
pl.col("space").is_null(),
6060
)
61-
bold_ref_rows = df.filter(
61+
bold_rows = df.filter(
6262
pl.col("ses") != "longitudinal",
6363
pl.col("datatype") == "func",
64+
pl.col("desc") == "preproc",
6465
pl.col("suffix") == "bold",
6566
pl.col("space").is_null(),
6667
)
67-
bold_ref = (
68-
None
69-
if bold_ref_rows.is_empty()
70-
else Path(bold_ref_rows["root"][0]) / bold_ref_rows["path"][0]
71-
)
7268

7369
inputs: list[TemplateInputs] = []
7470
skipped: list[str] = []
@@ -81,8 +77,18 @@ def discover_template_inputs(
8177
files = [
8278
Path(row["root"]) / row["path"] for row in sub_group.iter_rows(named=True)
8379
]
80+
# Filter for first found session; only single reference per task is needed
81+
sub_bold = bold_rows.filter(
82+
(pl.col("sub") == sub) & (pl.col("ses") == sessions[0])
83+
)
84+
bold_files = {
85+
row["task"]: Path(row["root"]) / row["path"]
86+
for row in sub_bold.iter_rows(named=True)
87+
}
8488
inputs.append(
85-
TemplateInputs(sub=sub, sessions=sessions, files=files, bold_ref=bold_ref)
89+
TemplateInputs(
90+
sub=sub, sessions=sessions, files=files, bold_files=bold_files
91+
)
8692
)
8793
return inputs, skipped
8894

@@ -96,8 +102,8 @@ def export_template(tpl: Bids, outputs: LongitudinalTemplateOutputs) -> None:
96102
outputs: Results from the longitudinal template workflow.
97103
"""
98104
tpl.save(outputs.template, suffix=Suffix.T1W)
99-
if outputs.bold_template is not None:
100-
tpl.save(outputs.bold_template, res="bold", suffix=Suffix.T1W)
105+
for btask, bold_template in outputs.bold_templates.items():
106+
tpl.save(bold_template, res=btask, suffix=Suffix.T1W)
101107
for ses, xfm in zip(outputs.sessions, outputs.transforms, strict=True):
102108
ses_label = bids_safe_label(ses)
103109
tpl.save(

src/rbc/orchestration/longitudinal/template.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def process_subject(
4949
sub=inputs.sub,
5050
sessions=inputs.sessions,
5151
in_files=inputs.files,
52-
bold_ref=inputs.bold_ref,
52+
bold_files=inputs.bold_files,
5353
)
5454
tpl = pipe_ctx.bids(datatype=Datatype.ANAT).derive(ses="longitudinal")
5555
export_template(tpl, outputs)

src/rbc/workflows/longitudinal/template.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from rbc.core.longitudinal.resampling import resample_img_to_bold_grid
1818

1919
if TYPE_CHECKING:
20-
from collections.abc import Sequence
20+
from collections.abc import Mapping, Sequence
2121
from pathlib import Path
2222

2323
_logger = logging.getLogger("rbc")
@@ -34,7 +34,7 @@ class LongitudinalTemplateOutputs(NamedTuple):
3434
"""
3535

3636
template: Path
37-
bold_template: Path | None
37+
bold_templates: dict[str, Path]
3838
sessions: list[str]
3939
transforms: list[Path]
4040

@@ -43,15 +43,15 @@ def generate_subject_template(
4343
sub: str,
4444
sessions: Sequence[str],
4545
in_files: Sequence[Path],
46-
bold_ref: Path | None = None,
46+
bold_files: Mapping[str, Path],
4747
) -> LongitudinalTemplateOutputs:
4848
"""Build a robust template and ITK transforms for one subject.
4949
5050
Args:
5151
sub: Subject label (without the ``sub-`` prefix).
5252
sessions: Session labels parallel to ``in_files``.
5353
in_files: Per-session preprocessed T1w volumes (e.g. brain-extracted).
54-
bold_ref: Reference bold volume to resample template for functional data.
54+
bold_files: Reference bold volumes to resample template for functional data.
5555
5656
Returns:
5757
:class:`LongitudinalTemplateOutputs` ready for BIDS export.
@@ -70,13 +70,15 @@ def generate_subject_template(
7070
in_xfms=robust.transforms,
7171
)
7272

73-
bold_template = (
74-
resample_img_to_bold_grid(bold_ref, robust.template) if bold_ref else None
75-
)
73+
_logger.info("Creating reference volumes for each functional task")
74+
bold_templates = {
75+
btask: resample_img_to_bold_grid(bfile, robust.template)
76+
for btask, bfile in bold_files.items()
77+
}
7678

7779
return LongitudinalTemplateOutputs(
7880
template=robust.template,
79-
bold_template=bold_template,
81+
bold_templates=bold_templates,
8082
sessions=list(sessions),
8183
transforms=itk_xfms,
8284
)

tests/unit/bids/test_longitudinal_template.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ def test_writes_template_and_xfms(self, tmp_path: Path) -> None:
155155

156156
outputs = LongitudinalTemplateOutputs(
157157
template=template_src,
158-
bold_template=template_bold_src,
158+
bold_templates={"test": template_bold_src},
159159
sessions=["baseline", "vis2"],
160160
transforms=[xfm_baseline, xfm_vis2],
161161
)

0 commit comments

Comments
 (0)