From d5bf9c73fe8c2800d6dcf7e8c87837b6d8d73bff Mon Sep 17 00:00:00 2001 From: Janhavi Pillai Date: Wed, 8 Apr 2026 18:42:22 -0400 Subject: [PATCH 1/6] longitudinal func outputs --- src/rbc/bids/functional.py | 6 ++ src/rbc/bids/longitudinal.py | 32 +++++++++-- src/rbc/cli/longitudinal.py | 12 +++- src/rbc/orchestration/longitudinal.py | 12 +++- src/rbc/workflows/functional.py | 81 ++++++++++++++++++++++----- tests/unit/bids/test_exports.py | 1 + 6 files changed, 122 insertions(+), 22 deletions(-) diff --git a/src/rbc/bids/functional.py b/src/rbc/bids/functional.py index 1991fd18..f1787a96 100644 --- a/src/rbc/bids/functional.py +++ b/src/rbc/bids/functional.py @@ -158,6 +158,12 @@ def export_functional( desc=bids_safe_label(reg), extension=".1D", ) + func.save( + outputs.bpf_regressor_file[reg], + suffix="regressorsBPF", + desc=bids_safe_label(reg), + extension=".1D", + ) mni = func.derive(space=TemplateSpace.MNI152NLIN6ASYM) for reg in regressors: diff --git a/src/rbc/bids/longitudinal.py b/src/rbc/bids/longitudinal.py index b0f52032..d4932a15 100644 --- a/src/rbc/bids/longitudinal.py +++ b/src/rbc/bids/longitudinal.py @@ -4,9 +4,10 @@ from typing import TYPE_CHECKING -from rbc.bids import Suffix, TemplateSpace +from rbc.bids import Suffix, TemplateSpace, bids_safe_label if TYPE_CHECKING: + from collections.abc import Sequence from pathlib import Path import polars as pl @@ -114,7 +115,8 @@ def resolve_longitudinal_func( tpl_df: pl.DataFrame, *, ses: str, -) -> dict[str, Path | None]: + regressors: Sequence[str], +) -> dict[str, Path | None | dict[str, Path]]: """Resolve inputs for longitudinal functional processing. Args: @@ -123,6 +125,7 @@ def resolve_longitudinal_func( func_df: DataFrame of functional derivatives. tpl_df: DataFrame of longitudinal template files. ses: Session label (used for template xfm lookup). + regressors: Regressor names (e.g. ``["36-parameter"]``). Returns: Dict with keys matching ``longitudinal_process`` parameters. @@ -146,9 +149,15 @@ def resolve_longitudinal_func( "bold": func_q.expect( func_df, suffix=Suffix.BOLD, desc="preproc", without=["space"] ), - "bold_mask": func_q.find( + "bold_mask": func_q.expect( func_df, suffix=Suffix.MASK, desc="brain", without=["space"] ), + "regressor_files": { + reg: func_q.expect( + func_df, suffix="regressors", desc=bids_safe_label(reg), extension=".1D" + ) + for reg in regressors + }, } @@ -167,5 +176,18 @@ def export_longitudinal_func(fex: Bids, outputs: FunctionalLongOutputs) -> None: desc="composite", extra={"from": "bold", "to": "longitudinal", "mode": "image"}, ) - if outputs.bold_mask: - fex.save(outputs.bold_mask, suffix=Suffix.MASK, desc="brain") + fex.save(outputs.bold_mask, suffix=Suffix.MASK, desc="brain") + for reg, path in outputs.regressed_bold.items(): + fex.save( + path, + suffix=Suffix.BOLD, + desc="regressed", + extra={"reg": bids_safe_label(reg)}, + ) + for reg, path in outputs.cleaned_bold.items(): + fex.save( + path, + suffix=Suffix.BOLD, + desc="preproc", + extra={"reg": bids_safe_label(reg)}, + ) diff --git a/src/rbc/cli/longitudinal.py b/src/rbc/cli/longitudinal.py index f6630157..4619ee0d 100644 --- a/src/rbc/cli/longitudinal.py +++ b/src/rbc/cli/longitudinal.py @@ -3,7 +3,7 @@ from __future__ import annotations from dataclasses import dataclass -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Literal from rbc.cli.base import BaseArgs, _or_default, _validate_nifti_path from rbc.orchestration import Filters, RunnerConfig @@ -23,6 +23,7 @@ class LongitudinalArgs(BaseArgs): anatomical: bool functional: bool registration_template: Path + regressor: Sequence[Literal["36-parameter", "aCompCor"]] @classmethod def validate_namespace(cls, ns: argparse.Namespace) -> LongitudinalArgs: @@ -38,6 +39,7 @@ def validate_namespace(cls, ns: argparse.Namespace) -> LongitudinalArgs: registration_template=_or_default( ns.anat_template, REGISTRATION_TEMPLATES.brain_1mm ), + regressor=ns.regressor, ) @@ -53,6 +55,7 @@ def main(args: LongitudinalArgs) -> int: anatomical=args.anatomical, functional=args.functional, registration_template=args.registration_template, + regressors=args.regressor, runner_config=RunnerConfig( runner=args.runner, verbose=bool(args.verbose), @@ -86,6 +89,13 @@ def register_command( action="store_true", help="Use functional longitudinal pipeline for processing", ) + parser.add_argument( + "--regressor", + nargs="+", + choices=["36-parameter", "aCompCor"], + default=["36-parameter"], + help="Space-delimited nuisance regression method(s) to apply.", + ) templates = parser.add_argument_group("template overrides") templates.add_argument( diff --git a/src/rbc/orchestration/longitudinal.py b/src/rbc/orchestration/longitudinal.py index ffadf2b7..96109290 100644 --- a/src/rbc/orchestration/longitudinal.py +++ b/src/rbc/orchestration/longitudinal.py @@ -75,6 +75,7 @@ def process_func( pipe_ctx: RunContext, func_df: pl.DataFrame, tpl_df: pl.DataFrame, + regressors: Sequence[str], ) -> None: """Handle functional longitudinal processing for one BOLD run. @@ -82,6 +83,7 @@ def process_func( pipe_ctx: RunContext bound to this subject/session. func_df: Functional derivative DataFrame for this run. tpl_df: Longitudinal template DataFrame. + regressors: Regressor names (e.g. ``["36-parameter"]``). """ row = func_df.filter(suffix=Suffix.BOLD).row(0, named=True) ents = extract_entities(row, ["task", "run"]) @@ -95,6 +97,7 @@ def process_func( func_df, tpl_df, ses=pipe_ctx.ses, # type: ignore[arg-type] + regressors=regressors, ) func_outputs = functional_longitudinal(**resolved) # type: ignore[arg-type] fex = func_q.derive(space="longitudinal") @@ -109,6 +112,7 @@ def run( anatomical: bool = True, functional: bool = True, registration_template: Path = REGISTRATION_TEMPLATES.brain_1mm, + regressors: Sequence[str] = ("36-parameter",), runner_config: RunnerConfig | None = None, ) -> None: """Run the longitudinal pipeline for all matching subjects/sessions. @@ -120,6 +124,7 @@ def run( anatomical: Run anatomical longitudinal processing. functional: Run functional longitudinal processing. registration_template: Brain template for ANTs registration. + regressors: Nuisance regressor strategies to apply (e.g. ``["36-parameter"]``). runner_config: Execution backend configuration. """ config = runner_config or RunnerConfig() @@ -173,7 +178,12 @@ def run( if functional: for func_df, _ in iter_session_files(session, groupby=FUNC_GROUP_ENTITIES): - process_func(pipe_ctx=pipe_ctx, func_df=func_df, tpl_df=tpl_df) + process_func( + pipe_ctx=pipe_ctx, + func_df=func_df, + tpl_df=tpl_df, + regressors=regressors, + ) pipe_ctx.ensure_dataset_description() diff --git a/src/rbc/workflows/functional.py b/src/rbc/workflows/functional.py index ce854aef..9bfbbfe8 100644 --- a/src/rbc/workflows/functional.py +++ b/src/rbc/workflows/functional.py @@ -81,7 +81,8 @@ class FunctionalOutputs(NamedTuple): template_bold: BOLD resampled to template space. regressed_bold: Nuisance-regressed & non-bandpassed BOLD. cleaned_bold: Nuisance-regressed & bandpass-filtered BOLD. - regressor_file: Bandpass-filtered nuisance regressor ``.1D`` file. + regressor_file: Nuisance regressor ``.1D`` files. + bpf_regressor_file: Bandpass-filtered nuisance regressor ``.1D`` files. template_brain_mask: Brain mask warped to template space. """ @@ -105,6 +106,7 @@ class FunctionalOutputs(NamedTuple): regressed_bold: dict[str, Path] cleaned_bold: dict[str, Path] regressor_file: dict[str, Path] + bpf_regressor_file: dict[str, Path] template_brain_mask: Path @@ -378,7 +380,8 @@ def single_session_preprocess( template_bold=template_bold, regressed_bold={r: regression[r].regressed_bold for r in regressor_set}, cleaned_bold={r: cleaned[r].regressed_bold for r in regressor_set}, - regressor_file=filtered_regressors, + regressor_file={r: regressors[r].regressor_file for r in regressor_set}, + bpf_regressor_file=filtered_regressors, template_brain_mask=tmpl_brain, ) @@ -392,12 +395,18 @@ class FunctionalLongOutputs(NamedTuple): bold: Preprocessed BOLD warped to longitudinal template space. bold_mask: Brain mask warped to longitudinal template space, or *None* if no mask was provided. + regressed_bold: Nuisance-regressed (non-bandpassed) BOLD in longitudinal + template space. Suitable for ALFF/fALFF. + cleaned_bold: Nuisance-regressed + bandpass-filtered BOLD in longitudinal + template space (Hallquist 2013). """ bold_to_long_xfm: Path sbref: Path bold: Path - bold_mask: Path | None = None + bold_mask: Path + regressed_bold: dict[str, Path] + cleaned_bold: dict[str, Path] def longitudinal_process( @@ -407,7 +416,8 @@ def longitudinal_process( bold_to_anat_itk: Path, sbref: Path, bold: Path, - bold_mask: Path | None, + bold_mask: Path, + regressor_files: dict[str, Path], ) -> FunctionalLongOutputs: """Transform preprocessed functional outputs to longitudinal template space. @@ -415,33 +425,74 @@ def longitudinal_process( composite warp is available, and anatomical data has already been processed to longitudinal template space. + Regressors are computed once during cross-sectional preprocessing and passed + in via ``regressor_files``. Only the regression steps are re-run against the + longitudinal space BOLD. + + Steps: + 1. Compose BOLD-to-anatomical + anatomical-to-longitudinal-template transforms. + 2. Warp sbref (3D) and preproc BOLD (4D) to longitudinal template space. + 3. Warp brain mask to longitudinal template space. + 4. Nuisance regression without bandpass on longitudinal-space BOLD + (for ALFF/fALFF). + 5. Nuisance regression with simultaneous bandpass filtering on longitudinal-space + BOLD (Hallquist 2013). + Args: template: Longitudinal template image. anat_to_template_xfm: T1w-to-longitudinal-template composite warp. bold_to_anat_itk: BOLD-to-T1w affine in ITK format. sbref: Motion reference (single-band reference) volume. bold: Preprocessed bold image. - bold_mask: Bold brain mask, if available. + bold_mask: Bold brain mask in native space. + regressor_files: Per-regressor nuisance regressor ``.1D`` files. + Returns: :class:`FunctionalLongOutputs` with all non-null inputs transformed to template space. """ + # 1. Compose full BOLD -> longitudinal template transform bold_to_tpl_xfm = compose_transform( ref=template, bold_to_anat_itk=bold_to_anat_itk, anat_to_tpl_xfm=anat_to_template_xfm, ) + # 2. Warp sbref & bold to longitudinal space + warped_sbref = func_transform( + in_file=sbref, template=template, xfm=bold_to_tpl_xfm, strategy="single" + ) + warped_bold = func_transform( + in_file=bold, template=template, xfm=bold_to_tpl_xfm, strategy="chunked" + ) + + # 3. Warp bold mask to longitudinal space + warped_mask = mask_transform(mask=bold_mask, template=template, xfm=bold_to_tpl_xfm) + + regression: dict[str, ApplyRegressionOutputs] = {} + cleaned: dict[str, ApplyRegressionOutputs] = {} + for reg, reg_file in regressor_files.items(): + # 4. Nuisance regression without bandpass + _logger.info("%s nuisance regression (no bandpass)", reg) + regression[reg] = apply_regression( + bold_file=warped_bold, + brain_mask_file=warped_mask, + regressor_file=reg_file, + ) + # 5. Simultaneous regression + bandpass filtering (Hallquist 2013) + _logger.info("%s nuisance regression + bandpass filtering", reg) + cleaned[reg] = apply_regression_bandpass( + bold_file=warped_bold, + brain_mask_file=warped_mask, + regressor_file=reg_file, + ) + return FunctionalLongOutputs( - sbref=func_transform( # 3D volume - in_file=sbref, template=template, xfm=bold_to_tpl_xfm, strategy="single" - ), - bold=func_transform( - in_file=bold, template=template, xfm=bold_to_tpl_xfm, strategy="chunked" - ), - bold_mask=mask_transform(mask=bold_mask, template=template, xfm=bold_to_tpl_xfm) - if bold_mask - else None, - bold_to_long_xfm=bold_to_tpl_xfm, + forward_xfm=bold_to_tpl_xfm, + sbref=warped_sbref, + bold=warped_bold, + bold_mask=warped_mask, + regressed_bold={r: regression[r].regressed_bold for r in regressor_files}, + cleaned_bold={r: cleaned[r].regressed_bold for r in regressor_files}, ) diff --git a/tests/unit/bids/test_exports.py b/tests/unit/bids/test_exports.py index 1c96faab..1de18258 100644 --- a/tests/unit/bids/test_exports.py +++ b/tests/unit/bids/test_exports.py @@ -74,6 +74,7 @@ def _make_func_outputs(w: Path, regressors: list[str]) -> FunctionalOutputs: regressed_bold={r: _dummy(w, f"regressed_{r}.nii.gz") for r in regressors}, cleaned_bold={r: _dummy(w, f"cleaned_{r}.nii.gz") for r in regressors}, regressor_file={r: _dummy(w, f"regressors_{r}.1D") for r in regressors}, + bpf_regressor_file={r: _dummy(w, f"bpf_regressors_{r}.1D") for r in regressors}, template_brain_mask=_dummy(w, "template_mask.nii.gz"), ) From 30d6d5fdc128daf88709c1b196b72e7881663968 Mon Sep 17 00:00:00 2001 From: Janhavi Pillai Date: Wed, 8 Apr 2026 18:57:38 -0400 Subject: [PATCH 2/6] rebase and tests --- src/rbc/orchestration/longitudinal.py | 2 +- tests/unit/cli/test_longitudinal.py | 1 + tests/unit/orchestration/test_longitudinal.py | 25 ++++++++++++++++--- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/rbc/orchestration/longitudinal.py b/src/rbc/orchestration/longitudinal.py index 96109290..24ff3167 100644 --- a/src/rbc/orchestration/longitudinal.py +++ b/src/rbc/orchestration/longitudinal.py @@ -105,7 +105,7 @@ def process_func( def run( - input_dirs: Sequence[Path], + input_dirs: list[Path], output_dir: Path, *, filters: Filters, diff --git a/tests/unit/cli/test_longitudinal.py b/tests/unit/cli/test_longitudinal.py index da966521..a631ac8c 100644 --- a/tests/unit/cli/test_longitudinal.py +++ b/tests/unit/cli/test_longitudinal.py @@ -30,6 +30,7 @@ def base_args(tmp_path: Path) -> argparse.Namespace: tmp_dir=None, anat_template=None, ants_threads=1, + regressor=["36-parameter"], ) diff --git a/tests/unit/orchestration/test_longitudinal.py b/tests/unit/orchestration/test_longitudinal.py index ca28e510..e0e3c0bf 100644 --- a/tests/unit/orchestration/test_longitudinal.py +++ b/tests/unit/orchestration/test_longitudinal.py @@ -68,6 +68,8 @@ def _mock_func_outputs(*, with_bold_mask: bool = True) -> Mock: m.bold = fake / "bold.nii.gz" m.bold_to_long_xfm = fake / "bold_to_long_xfm.nii.gz" m.bold_mask = (fake / "bold_mask.nii.gz") if with_bold_mask else None + m.regressed_bold = {"36-parameter": fake / "regressed.nii.gz"} + m.cleaned_bold = {"36-parameter": fake / "cleaned.nii.gz"} return m @@ -319,7 +321,12 @@ def test_calls_functional_longitudinal( ), patch("rbc.bids.builder.shutil.copy2"), ): - process_func(pipe_ctx=pipe_ctx, func_df=func_df, tpl_df=tpl_df) + process_func( + pipe_ctx=pipe_ctx, + func_df=func_df, + tpl_df=tpl_df, + regressors=["36-parameter"], + ) assert mock_func.call_count == 1 @pytest.mark.parametrize( @@ -359,7 +366,12 @@ def test_missing_required_file_raises( ), pytest.raises(FileNotFoundError), ): - process_func(pipe_ctx=pipe_ctx, func_df=func_df, tpl_df=tpl_df) + process_func( + pipe_ctx=pipe_ctx, + func_df=func_df, + tpl_df=tpl_df, + regressors=["36-parameter"], + ) def test_optional_bold_mask_file_not_found( self, func_df: pl.DataFrame, tpl_df: pl.DataFrame, tmp_path: Path @@ -377,8 +389,13 @@ def test_optional_bold_mask_file_not_found( ), patch("rbc.bids.builder.shutil.copy2") as mock_copy, ): - process_func(pipe_ctx=pipe_ctx, func_df=func_df, tpl_df=tpl_df) - assert mock_copy.call_count == 3 + process_func( + pipe_ctx=pipe_ctx, + func_df=func_df, + tpl_df=tpl_df, + regressors=["36-parameter"], + ) + assert mock_copy.call_count == 5 class TestLongitudinalDispatch: From beecfe3d0fd4dea8fc726e8d344a07aee2036a67 Mon Sep 17 00:00:00 2001 From: Janhavi Pillai Date: Wed, 8 Apr 2026 19:11:05 -0400 Subject: [PATCH 3/6] inputs and tests --- src/rbc/cli/longitudinal.py | 2 +- src/rbc/workflows/functional.py | 3 +-- tests/unit/bids/test_exports.py | 4 ++-- tests/unit/orchestration/test_longitudinal.py | 24 ------------------- 4 files changed, 4 insertions(+), 29 deletions(-) diff --git a/src/rbc/cli/longitudinal.py b/src/rbc/cli/longitudinal.py index 4619ee0d..be8c3697 100644 --- a/src/rbc/cli/longitudinal.py +++ b/src/rbc/cli/longitudinal.py @@ -46,7 +46,7 @@ def validate_namespace(cls, ns: argparse.Namespace) -> LongitudinalArgs: def main(args: LongitudinalArgs) -> int: """Main entrypoint of longitudinal workflow.""" run( - input_dirs=args.input_dirs, + input_dirs=list(args.input_dirs), output_dir=args.output_dir, filters=Filters( participant_label=args.participant_label, diff --git a/src/rbc/workflows/functional.py b/src/rbc/workflows/functional.py index 9bfbbfe8..953d3abb 100644 --- a/src/rbc/workflows/functional.py +++ b/src/rbc/workflows/functional.py @@ -393,8 +393,7 @@ class FunctionalLongOutputs(NamedTuple): bold_to_long_xfm: BOLD-to-longitudinal-template composite warp. sbref: Motion reference volume warped to longitudinal template space. bold: Preprocessed BOLD warped to longitudinal template space. - bold_mask: Brain mask warped to longitudinal template space, - or *None* if no mask was provided. + bold_mask: Brain mask warped to longitudinal template space. regressed_bold: Nuisance-regressed (non-bandpassed) BOLD in longitudinal template space. Suitable for ALFF/fALFF. cleaned_bold: Nuisance-regressed + bandpass-filtered BOLD in longitudinal diff --git a/tests/unit/bids/test_exports.py b/tests/unit/bids/test_exports.py index 1de18258..53b65d1a 100644 --- a/tests/unit/bids/test_exports.py +++ b/tests/unit/bids/test_exports.py @@ -202,7 +202,7 @@ def test_file_count_single_regressor( outputs = _make_func_outputs(workdir, ["36-parameter"]) export_functional(func_bids, outputs, regressors=["36-parameter"]) saved = list(pipe_ctx.output_dir.rglob("*.*")) - assert len(saved) == 13 + assert len(saved) == 14 def test_file_count_two_regressors( self, func_bids: Bids, workdir: Path, pipe_ctx: RunContext @@ -215,7 +215,7 @@ def test_file_count_two_regressors( outputs = _make_func_outputs(workdir, regs) export_functional(func_bids, outputs, regressors=regs) saved = list(pipe_ctx.output_dir.rglob("*.*")) - assert len(saved) == 16 + assert len(saved) == 18 # --------------------------------------------------------------------------- diff --git a/tests/unit/orchestration/test_longitudinal.py b/tests/unit/orchestration/test_longitudinal.py index e0e3c0bf..0e436e9a 100644 --- a/tests/unit/orchestration/test_longitudinal.py +++ b/tests/unit/orchestration/test_longitudinal.py @@ -373,30 +373,6 @@ def test_missing_required_file_raises( regressors=["36-parameter"], ) - def test_optional_bold_mask_file_not_found( - self, func_df: pl.DataFrame, tpl_df: pl.DataFrame, tmp_path: Path - ) -> None: - """Optional bold_mask not found is caught; 3 exports emitted.""" - pipe_ctx = RunContext(sub="01", ses="baseline", output_dir=tmp_path) - with ( - patch( - "rbc.orchestration.longitudinal.functional_longitudinal", - return_value=_mock_func_outputs(with_bold_mask=False), - ), - patch( - "rbc.bids.query.find_file", - side_effect=_none_for(suffix="mask", desc="brain"), - ), - patch("rbc.bids.builder.shutil.copy2") as mock_copy, - ): - process_func( - pipe_ctx=pipe_ctx, - func_df=func_df, - tpl_df=tpl_df, - regressors=["36-parameter"], - ) - assert mock_copy.call_count == 5 - class TestLongitudinalDispatch: """Tests for run() dispatch logic (not filtering, which is in test_filters).""" From 45babbc8cd7aedeace53f120f13657ce73a9c867 Mon Sep 17 00:00:00 2001 From: Janhavi Pillai Date: Wed, 8 Apr 2026 19:42:38 -0400 Subject: [PATCH 4/6] bpf regressors naming --- src/rbc/bids/functional.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rbc/bids/functional.py b/src/rbc/bids/functional.py index f1787a96..69b8a460 100644 --- a/src/rbc/bids/functional.py +++ b/src/rbc/bids/functional.py @@ -160,7 +160,7 @@ def export_functional( ) func.save( outputs.bpf_regressor_file[reg], - suffix="regressorsBPF", + suffix="regressors+filtered", desc=bids_safe_label(reg), extension=".1D", ) From d4fa65139d86ee5c970c2dcce61eb6ddc4490952 Mon Sep 17 00:00:00 2001 From: Janhavi Pillai Date: Thu, 9 Apr 2026 11:08:01 -0400 Subject: [PATCH 5/6] changes --- src/rbc/bids/longitudinal.py | 16 ++++++++++++++-- src/rbc/cli/longitudinal.py | 2 +- src/rbc/orchestration/longitudinal.py | 5 +++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/rbc/bids/longitudinal.py b/src/rbc/bids/longitudinal.py index d4932a15..30bd8849 100644 --- a/src/rbc/bids/longitudinal.py +++ b/src/rbc/bids/longitudinal.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, TypedDict from rbc.bids import Suffix, TemplateSpace, bids_safe_label @@ -108,6 +108,18 @@ def export_longitudinal_anat(aex: Bids, outputs: AnatomicalLongOutputs) -> None: ) +class LongitudinalFuncInputs(TypedDict): + """Resolved inputs for the longitudinal functional workflow.""" + + template: Path + anat_to_template_xfm: Path + bold_to_anat_itk: Path + sbref: Path + bold: Path + bold_mask: Path + regressor_files: dict[str, Path] + + def resolve_longitudinal_func( func_q: Bids, tpl_q: Bids, @@ -116,7 +128,7 @@ def resolve_longitudinal_func( *, ses: str, regressors: Sequence[str], -) -> dict[str, Path | None | dict[str, Path]]: +) -> LongitudinalFuncInputs: """Resolve inputs for longitudinal functional processing. Args: diff --git a/src/rbc/cli/longitudinal.py b/src/rbc/cli/longitudinal.py index be8c3697..4619ee0d 100644 --- a/src/rbc/cli/longitudinal.py +++ b/src/rbc/cli/longitudinal.py @@ -46,7 +46,7 @@ def validate_namespace(cls, ns: argparse.Namespace) -> LongitudinalArgs: def main(args: LongitudinalArgs) -> int: """Main entrypoint of longitudinal workflow.""" run( - input_dirs=list(args.input_dirs), + input_dirs=args.input_dirs, output_dir=args.output_dir, filters=Filters( participant_label=args.participant_label, diff --git a/src/rbc/orchestration/longitudinal.py b/src/rbc/orchestration/longitudinal.py index 24ff3167..4c4a3a9f 100644 --- a/src/rbc/orchestration/longitudinal.py +++ b/src/rbc/orchestration/longitudinal.py @@ -17,6 +17,7 @@ load_table, ) from rbc.bids.longitudinal import ( + LongitudinalFuncInputs, export_longitudinal_anat, export_longitudinal_func, resolve_longitudinal_anat, @@ -91,7 +92,7 @@ def process_func( func_q = pipe_ctx.bids(datatype=Datatype.FUNC, entities=ents) tpl_q = pipe_ctx.bids(datatype=Datatype.ANAT).derive(ses="longitudinal") - resolved = resolve_longitudinal_func( + resolved: LongitudinalFuncInputs = resolve_longitudinal_func( func_q, tpl_q, func_df, @@ -105,7 +106,7 @@ def process_func( def run( - input_dirs: list[Path], + input_dirs: Sequence[Path], output_dir: Path, *, filters: Filters, From 90cd3712cc80662dcaa65f38f54643462f3a54c7 Mon Sep 17 00:00:00 2001 From: Janhavi Pillai Date: Fri, 10 Apr 2026 13:14:44 -0700 Subject: [PATCH 6/6] fix args --- src/rbc/workflows/functional.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rbc/workflows/functional.py b/src/rbc/workflows/functional.py index 953d3abb..c1ca61a2 100644 --- a/src/rbc/workflows/functional.py +++ b/src/rbc/workflows/functional.py @@ -488,7 +488,7 @@ def longitudinal_process( ) return FunctionalLongOutputs( - forward_xfm=bold_to_tpl_xfm, + bold_to_long_xfm=bold_to_tpl_xfm, sbref=warped_sbref, bold=warped_bold, bold_mask=warped_mask,