|
8 | 8 |
|
9 | 9 | """ |
10 | 10 | from pathlib import Path |
11 | | -from itertools import groupby |
12 | 11 | import warnings |
13 | 12 | import re |
14 | 13 | import simplejson as json |
@@ -163,22 +162,9 @@ def collect_data(dataset, participant_label, task=None, echo=None): |
163 | 162 | subj_data = {modality: [x.filename for x in layout.get(**query)] |
164 | 163 | for modality, query in queries.items()} |
165 | 164 |
|
166 | | - def _grp_echos(x): |
167 | | - if '_echo-' not in x: |
168 | | - return x |
169 | | - echo = re.search("_echo-\\d*", x).group(0) |
170 | | - return x.replace(echo, "_echo-?") |
171 | | - |
172 | | - if subj_data["bold"]: |
173 | | - bold_sess = subj_data["bold"] |
174 | | - |
175 | | - if any(['_echo-' in bold for bold in bold_sess]): |
176 | | - ses_uids = [list(bold) for _, bold in groupby(bold_sess, key=_grp_echos)] |
177 | | - ses_uids = [x[0] if len(x) == 1 else x for x in ses_uids] |
178 | | - else: |
179 | | - ses_uids = bold_sess |
180 | | - |
181 | | - subj_data.update({"bold": ses_uids}) |
| 165 | + # Special case: multi-echo BOLD, grouping echos |
| 166 | + if any(['_echo-' in bold for bold in subj_data['bold']]): |
| 167 | + subj_data['bold'] = group_multiecho(subj_data['bold']) |
182 | 168 |
|
183 | 169 | return subj_data, layout |
184 | 170 |
|
@@ -241,3 +227,95 @@ def get_metadata_for_nifti(in_file): |
241 | 227 | json.loads(json_file_path.read_text())) |
242 | 228 |
|
243 | 229 | return merged_param_dict |
| 230 | + |
| 231 | + |
| 232 | +def group_multiecho(bold_sess): |
| 233 | + """ |
| 234 | + Multiplexes multi-echo EPIs into arrays. Dual-echo is a special |
| 235 | + case of multi-echo, which is treated as single-echo data. |
| 236 | +
|
| 237 | + >>> bold_sess = ["sub-01_task-rest_echo-1_run-01_bold.nii.gz", |
| 238 | + ... "sub-01_task-rest_echo-2_run-01_bold.nii.gz", |
| 239 | + ... "sub-01_task-rest_echo-1_run-02_bold.nii.gz", |
| 240 | + ... "sub-01_task-rest_echo-2_run-02_bold.nii.gz", |
| 241 | + ... "sub-01_task-rest_echo-3_run-02_bold.nii.gz", |
| 242 | + ... "sub-01_task-rest_run-03_bold.nii.gz"] |
| 243 | + >>> group_multiecho(bold_sess) |
| 244 | + ['sub-01_task-rest_echo-1_run-01_bold.nii.gz', |
| 245 | + 'sub-01_task-rest_echo-2_run-01_bold.nii.gz', |
| 246 | + ['sub-01_task-rest_echo-1_run-02_bold.nii.gz', |
| 247 | + 'sub-01_task-rest_echo-2_run-02_bold.nii.gz', |
| 248 | + 'sub-01_task-rest_echo-3_run-02_bold.nii.gz'], |
| 249 | + 'sub-01_task-rest_run-03_bold.nii.gz'] |
| 250 | +
|
| 251 | + >>> bold_sess.insert(2, "sub-01_task-rest_echo-3_run-01_bold.nii.gz") |
| 252 | + >>> group_multiecho(bold_sess) |
| 253 | + [['sub-01_task-rest_echo-1_run-01_bold.nii.gz', |
| 254 | + 'sub-01_task-rest_echo-2_run-01_bold.nii.gz', |
| 255 | + 'sub-01_task-rest_echo-3_run-01_bold.nii.gz'], |
| 256 | + ['sub-01_task-rest_echo-1_run-02_bold.nii.gz', |
| 257 | + 'sub-01_task-rest_echo-2_run-02_bold.nii.gz', |
| 258 | + 'sub-01_task-rest_echo-3_run-02_bold.nii.gz'], |
| 259 | + 'sub-01_task-rest_run-03_bold.nii.gz'] |
| 260 | +
|
| 261 | + >>> bold_sess += ["sub-01_task-beh_echo-1_run-01_bold.nii.gz", |
| 262 | + ... "sub-01_task-beh_echo-2_run-01_bold.nii.gz", |
| 263 | + ... "sub-01_task-beh_echo-1_run-02_bold.nii.gz", |
| 264 | + ... "sub-01_task-beh_echo-2_run-02_bold.nii.gz", |
| 265 | + ... "sub-01_task-beh_echo-3_run-02_bold.nii.gz", |
| 266 | + ... "sub-01_task-beh_run-03_bold.nii.gz"] |
| 267 | + >>> group_multiecho(bold_sess) |
| 268 | + [['sub-01_task-rest_echo-1_run-01_bold.nii.gz', |
| 269 | + 'sub-01_task-rest_echo-2_run-01_bold.nii.gz', |
| 270 | + 'sub-01_task-rest_echo-3_run-01_bold.nii.gz'], |
| 271 | + ['sub-01_task-rest_echo-1_run-02_bold.nii.gz', |
| 272 | + 'sub-01_task-rest_echo-2_run-02_bold.nii.gz', |
| 273 | + 'sub-01_task-rest_echo-3_run-02_bold.nii.gz'], |
| 274 | + 'sub-01_task-rest_run-03_bold.nii.gz', |
| 275 | + 'sub-01_task-beh_echo-1_run-01_bold.nii.gz', |
| 276 | + 'sub-01_task-beh_echo-2_run-01_bold.nii.gz', |
| 277 | + ['sub-01_task-beh_echo-1_run-02_bold.nii.gz', |
| 278 | + 'sub-01_task-beh_echo-2_run-02_bold.nii.gz', |
| 279 | + 'sub-01_task-beh_echo-3_run-02_bold.nii.gz'], |
| 280 | + 'sub-01_task-beh_run-03_bold.nii.gz'] |
| 281 | +
|
| 282 | + Some tests from https://neurostars.org/t/fmriprep-from\ |
| 283 | +-singularity-unboundlocalerror/3299/7 |
| 284 | +
|
| 285 | + >>> bold_sess = ['sub-01_task-AudLoc_echo-1_bold.nii', |
| 286 | + ... 'sub-01_task-AudLoc_echo-2_bold.nii', |
| 287 | + ... 'sub-01_task-FJT_echo-1_bold.nii', |
| 288 | + ... 'sub-01_task-FJT_echo-2_bold.nii', |
| 289 | + ... 'sub-01_task-LDT_echo-1_bold.nii', |
| 290 | + ... 'sub-01_task-LDT_echo-2_bold.nii', |
| 291 | + ... 'sub-01_task-MotLoc_echo-1_bold.nii', |
| 292 | + ... 'sub-01_task-MotLoc_echo-2_bold.nii'] |
| 293 | + >>> group_multiecho(bold_sess) == bold_sess |
| 294 | + True |
| 295 | +
|
| 296 | + >>> bold_sess += ['sub-01_task-MotLoc_echo-3_bold.nii'] |
| 297 | + >>> groups = group_multiecho(bold_sess) |
| 298 | + >>> len(groups[:-1]) |
| 299 | + 6 |
| 300 | + >>> [isinstance(g, list) for g in groups] |
| 301 | + [False, False, False, False, False, False, True] |
| 302 | + >>> len(groups[-1]) |
| 303 | + 3 |
| 304 | +
|
| 305 | +
|
| 306 | + """ |
| 307 | + from itertools import groupby |
| 308 | + |
| 309 | + def _grp_echos(x): |
| 310 | + if '_echo-' not in x: |
| 311 | + return x |
| 312 | + echo = re.search("_echo-\\d*", x).group(0) |
| 313 | + return x.replace(echo, "_echo-?") |
| 314 | + |
| 315 | + ses_uids = [] |
| 316 | + for _, bold in groupby(bold_sess, key=_grp_echos): |
| 317 | + bold = list(bold) |
| 318 | + # If single- or dual-echo, flatten list; keep list otherwise. |
| 319 | + action = getattr(ses_uids, 'append' if len(bold) > 2 else 'extend') |
| 320 | + action(bold) |
| 321 | + return ses_uids |
0 commit comments