88from __future__ import annotations
99
1010from dataclasses import dataclass
11- from pathlib import Path
1211from typing import TYPE_CHECKING , Literal
1312
1413import polars as pl
1514from tqdm import tqdm
1615
17- from rbc .bids import (
18- ANAT_GROUP_ENTITIES ,
19- FUNC_GROUP_ENTITIES ,
20- SUB_SES_QUERY ,
21- Datatype ,
22- extract_entities ,
23- load_table ,
24- )
25- from rbc .bids .anatomical import export_anatomical
26- from rbc .bids .functional import export_functional
16+ from rbc .bids import SUB_SES_QUERY , Datatype , load_table
17+ from rbc .bids .anatomical import discover_anatomical , export_anatomical
18+ from rbc .bids .functional import discover_functional , export_functional
2719from rbc .bids .metrics import export_metrics
2820from rbc .bids .qc import export_qc
29- from rbc .bids .session import iter_session_files , load_session
21+ from rbc .bids .session import load_session
3022from rbc .cli import _DEFAULT_ENV_VARS
3123from rbc .cli .base import BaseArgs , _validate_atlas , _validate_positive , _validate_task
3224from rbc .context import RunContext
@@ -109,32 +101,22 @@ def main(args: AllArgs) -> int:
109101 session = load_session (sub_ses_group , pipe_ctx .sub , pipe_ctx .ses )
110102
111103 # --- Anatomical (once per session, first T1w) ---
112- for _ , anat_df in session .anat .filter (pl .col ("suffix" ) == "T1w" ).group_by (
113- ANAT_GROUP_ENTITIES , maintain_order = True
114- ):
115- anat_row = anat_df .filter (suffix = "T1w" ).row (0 , named = True )
116- t1w_fpath = Path (anat_row ["root" ]) / anat_row ["path" ]
117- ents = extract_entities (anat_row , ["run" , "acq" , "rec" , "echo" ])
118- ctx .logger .info (f"Anatomical: { t1w_fpath } " )
104+ for anat_run in discover_anatomical (session ):
105+ ctx .logger .info (f"Anatomical: { anat_run .path } " )
119106
120- anat_outputs = anatomical_preprocess (in_t1w = t1w_fpath )
107+ anat_outputs = anatomical_preprocess (in_t1w = anat_run . path )
121108
122- anat = pipe_ctx .bids (datatype = Datatype .ANAT , entities = ents )
109+ anat = pipe_ctx .bids (datatype = Datatype .ANAT , entities = anat_run . entities )
123110 export_anatomical (anat , anat_outputs )
124111
125112 # --- Functional + Metrics + QC (per BOLD run) ---
126- for func_df , _anat_df in iter_session_files (
127- session , groupby = FUNC_GROUP_ENTITIES
128- ):
129- row = func_df .row (0 , named = True )
130- bold_fpath = Path (row ["root" ]) / row ["path" ]
131- ents = extract_entities (row , ["task" , "run" , "acq" , "rec" , "dir" , "echo" ])
132- ctx .logger .info (f"Functional: { bold_fpath } " )
113+ for func_run in discover_functional (session ):
114+ ctx .logger .info (f"Functional: { func_run .path } " )
133115
134- func_metadata = FunctionalMetadata .load (bold_fpath , tr_override = args .tr )
116+ func_metadata = FunctionalMetadata .load (func_run . path , tr_override = args .tr )
135117
136118 func_outputs = functional_preprocess (
137- in_bold = bold_fpath ,
119+ in_bold = func_run . path ,
138120 t1w_brain = anat_outputs .brain ,
139121 wm_bbr_mask = anat_outputs .wm_bbr_mask ,
140122 brain_mask = anat_outputs .brain_mask ,
@@ -146,14 +128,16 @@ def main(args: AllArgs) -> int:
146128 regressor_set = args .regressor ,
147129 )
148130
149- func = pipe_ctx .bids (datatype = Datatype .FUNC , entities = ents )
131+ func = pipe_ctx .bids (datatype = Datatype .FUNC , entities = func_run . entities )
150132 mni = export_functional (func , func_outputs , regressors = args .regressor )
151133
152134 # --- Metrics ---
153135 for regressor in args .regressor :
136+ task = func_run .entities .get ("task" , "" )
137+ run = func_run .entities .get ("run" , 0 )
154138 ctx .logger .info (
155- f"Metrics: sub-{ pipe_ctx .sub } task-{ ents . get ( ' task' , '' ) } "
156- f"run-{ ents . get ( ' run' , 0 ) } regressor-{ regressor } "
139+ f"Metrics: sub-{ pipe_ctx .sub } task-{ task } "
140+ f"run-{ run } regressor-{ regressor } "
157141 )
158142 metrics_outputs = metrics_pipeline (
159143 regressed_bold = func_outputs .regressed_bold [regressor ],
@@ -172,10 +156,7 @@ def main(args: AllArgs) -> int:
172156 )
173157
174158 # --- QC ---
175- ctx .logger .info (
176- f"QC: sub-{ pipe_ctx .sub } "
177- f"task-{ ents .get ('task' , '' )} run-{ ents .get ('run' , 0 )} "
178- )
159+ ctx .logger .info (f"QC: sub-{ pipe_ctx .sub } task-{ task } run-{ run } " )
179160 qc_outputs = qc_pipeline (
180161 template_bold = func_outputs .template_bold ,
181162 cleaned_bold = func_outputs .cleaned_bold ,
@@ -187,19 +168,16 @@ def main(args: AllArgs) -> int:
187168 template_brain_mask = func_outputs .template_brain_mask ,
188169 sub = pipe_ctx .sub ,
189170 ses = pipe_ctx .ses or "" ,
190- task = ents .get ("task" , "" ),
191- run = ents .get ("run" , 0 ),
171+ task = func_run . entities .get ("task" , "" ),
172+ run = func_run . entities .get ("run" , 0 ),
192173 start_tr = args .start_tr ,
193174 regressor_set = args .regressor ,
194175 )
195176
196177 export_qc (mni , qc_outputs , regressors = args .regressor )
197178
198179 status = "PASSED" if qc_outputs .passed else "FAILED"
199- ctx .logger .info (
200- f"QC { status } for sub-{ pipe_ctx .sub } task-{ ents .get ('task' , '' )} "
201- f"run-{ ents .get ('run' , 0 )} "
202- )
180+ ctx .logger .info (f"QC { status } for sub-{ pipe_ctx .sub } task-{ task } run-{ run } " )
203181 pipe_ctx .ensure_dataset_description ()
204182
205183 ctx .logger .info ("RBC full pipeline complete" )
0 commit comments