|
1 | | -# Copyright (C) 2012-2024 C-PAC Developers |
| 1 | +# Copyright (C) 2012-2025 C-PAC Developers |
2 | 2 |
|
3 | 3 | # This file is part of C-PAC. |
4 | 4 |
|
|
16 | 16 | # License along with C-PAC. If not, see <https://www.gnu.org/licenses/>. |
17 | 17 | """Functions for calculating motion parameters.""" |
18 | 18 |
|
19 | | -# pylint: disable=ungrouped-imports,wrong-import-order,wrong-import-position |
| 19 | +from typing import Literal |
| 20 | + |
20 | 21 | from nipype.interfaces import afni, fsl, utility as util |
21 | 22 | from nipype.interfaces.afni import preprocess, utils as afni_utils |
22 | 23 |
|
|
31 | 32 | motion_power_statistics, |
32 | 33 | ) |
33 | 34 | from CPAC.pipeline import nipype_pipeline_engine as pe |
| 35 | +from CPAC.pipeline.engine import ResourcePool |
34 | 36 | from CPAC.pipeline.nodeblock import nodeblock |
35 | 37 | from CPAC.pipeline.schema import valid_options |
| 38 | +from CPAC.utils.configuration import Configuration |
36 | 39 | from CPAC.utils.interfaces.function import Function |
37 | 40 | from CPAC.utils.utils import check_prov_for_motion_tool |
38 | 41 |
|
@@ -364,79 +367,97 @@ def get_mcflirt_rms_abs(rms_files): |
364 | 367 | "motion_correction", |
365 | 368 | "motion_correction_reference", |
366 | 369 | ], |
367 | | - option_val=["mean", "median", "selected_volume", "fmriprep_reference"], |
368 | | - inputs=["desc-preproc_bold", "desc-reorient_bold"], |
| 370 | + option_val=["mean", "median", "selected_volume"], |
| 371 | + inputs=["desc-preproc_bold"], |
369 | 372 | outputs=["motion-basefile"], |
370 | 373 | ) |
371 | | -def get_motion_ref(wf, cfg, strat_pool, pipe_num, opt=None): |
372 | | - if opt not in get_motion_ref.option_val: |
373 | | - msg = ( |
374 | | - "\n\n[!] Error: The 'motion_correction_reference' " |
375 | | - "parameter of the 'motion_correction' workflow " |
376 | | - "must be one of:\n\t{0}.\n\nTool input: '{1}'" |
377 | | - "\n\n".format( |
378 | | - " or ".join([f"'{val}'" for val in get_motion_ref.option_val]), opt |
| 374 | +def get_motion_ref( |
| 375 | + wf: pe.Workflow, |
| 376 | + cfg: Configuration, |
| 377 | + strat_pool: ResourcePool, |
| 378 | + pipe_num: int, |
| 379 | + opt: Literal["mean", "median", "selected_volume"], |
| 380 | +) -> tuple[pe.Workflow, dict[str, tuple[pe.Node, str]]]: |
| 381 | + """Get the reference image for motion correction.""" |
| 382 | + node, out = strat_pool.get_data("desc-preproc_bold") |
| 383 | + in_label = "in_file" |
| 384 | + match opt: |
| 385 | + case "mean": |
| 386 | + func_get_RPI = pe.Node( |
| 387 | + interface=afni_utils.TStat(options="-mean"), |
| 388 | + name=f"func_get_mean_RPI_{pipe_num}", |
| 389 | + mem_gb=0.48, |
| 390 | + mem_x=(1435097126797993 / 302231454903657293676544, in_label), |
379 | 391 | ) |
380 | | - ) |
381 | | - raise ValueError(msg) |
382 | | - |
383 | | - if opt == "mean": |
384 | | - func_get_RPI = pe.Node( |
385 | | - interface=afni_utils.TStat(), |
386 | | - name=f"func_get_mean_RPI_{pipe_num}", |
387 | | - mem_gb=0.48, |
388 | | - mem_x=(1435097126797993 / 302231454903657293676544, "in_file"), |
389 | | - ) |
390 | | - |
391 | | - func_get_RPI.inputs.options = "-mean" |
392 | | - func_get_RPI.inputs.outputtype = "NIFTI_GZ" |
393 | | - |
394 | | - node, out = strat_pool.get_data("desc-preproc_bold") |
395 | | - wf.connect(node, out, func_get_RPI, "in_file") |
396 | | - |
397 | | - elif opt == "median": |
398 | | - func_get_RPI = pe.Node( |
399 | | - interface=afni_utils.TStat(), name=f"func_get_median_RPI_{pipe_num}" |
400 | | - ) |
401 | | - |
402 | | - func_get_RPI.inputs.options = "-median" |
403 | | - func_get_RPI.inputs.outputtype = "NIFTI_GZ" |
404 | | - |
405 | | - node, out = strat_pool.get_data("desc-preproc_bold") |
406 | | - wf.connect(node, out, func_get_RPI, "in_file") |
407 | | - |
408 | | - elif opt == "selected_volume": |
409 | | - func_get_RPI = pe.Node( |
410 | | - interface=afni.Calc(), name=f"func_get_selected_RPI_{pipe_num}" |
411 | | - ) |
412 | | - |
413 | | - func_get_RPI.inputs.set( |
414 | | - expr="a", |
415 | | - single_idx=cfg.functional_preproc["motion_estimates_and_correction"][ |
416 | | - "motion_correction" |
417 | | - ]["motion_correction_reference_volume"], |
418 | | - outputtype="NIFTI_GZ", |
419 | | - ) |
| 392 | + case "median": |
| 393 | + func_get_RPI = pe.Node( |
| 394 | + interface=afni_utils.TStat(options="-median"), |
| 395 | + name=f"func_get_median_RPI_{pipe_num}", |
| 396 | + ) |
| 397 | + case "selected_volume": |
| 398 | + func_get_RPI = pe.Node( |
| 399 | + interface=afni.Calc( |
| 400 | + expr="a", |
| 401 | + single_idx=cfg.functional_preproc[ |
| 402 | + "motion_estimates_and_correction" |
| 403 | + ]["motion_correction"]["motion_correction_reference_volume"], |
| 404 | + ), |
| 405 | + name=f"func_get_selected_RPI_{pipe_num}", |
| 406 | + ) |
| 407 | + in_label = "in_file_a" |
| 408 | + case _: |
| 409 | + msg = ( |
| 410 | + "\n\n[!] Error: The 'motion_correction_reference' " |
| 411 | + "parameter of the 'motion_correction' workflow " |
| 412 | + "must be one of:\n\t{0}.\n\nTool input: '{1}'" |
| 413 | + "\n\n".format( |
| 414 | + " or ".join([f"'{val}'" for val in get_motion_ref.option_val]), opt |
| 415 | + ) |
| 416 | + ) |
| 417 | + raise ValueError(msg) |
| 418 | + func_get_RPI.inputs.outputtype = "NIFTI_GZ" |
| 419 | + wf.connect(node, out, func_get_RPI, in_label) |
| 420 | + outputs = {"motion-basefile": (func_get_RPI, "out_file")} |
| 421 | + return wf, outputs |
420 | 422 |
|
421 | | - node, out = strat_pool.get_data("desc-preproc_bold") |
422 | | - wf.connect(node, out, func_get_RPI, "in_file_a") |
423 | 423 |
|
424 | | - elif opt == "fmriprep_reference": |
425 | | - func_get_RPI = pe.Node( |
426 | | - Function( |
427 | | - input_names=["in_file"], |
428 | | - output_names=["out_file"], |
429 | | - function=estimate_reference_image, |
430 | | - ), |
431 | | - name=f"func_get_fmriprep_ref_{pipe_num}", |
432 | | - ) |
| 424 | +@nodeblock( |
| 425 | + name="get_motion_ref_fmriprep", |
| 426 | + switch=["functional_preproc", "motion_estimates_and_correction", "run"], |
| 427 | + option_key=[ |
| 428 | + "functional_preproc", |
| 429 | + "motion_estimates_and_correction", |
| 430 | + "motion_correction", |
| 431 | + "motion_correction_reference", |
| 432 | + ], |
| 433 | + option_val=["fmriprep_reference"], |
| 434 | + inputs=["desc-reorient_bold"], |
| 435 | + outputs=["motion-basefile"], |
| 436 | +) |
| 437 | +def get_motion_ref_fmriprep( |
| 438 | + wf: pe.Workflow, |
| 439 | + cfg: Configuration, |
| 440 | + strat_pool: ResourcePool, |
| 441 | + pipe_num: int, |
| 442 | + opt: Literal["fmriprep_reference"], |
| 443 | +) -> tuple[pe.Workflow, dict[str, tuple[pe.Node, str]]]: |
| 444 | + """Get the fMRIPrep-style reference image for motion correction.""" |
| 445 | + assert opt == "fmriprep_reference" |
| 446 | + func_get_RPI = pe.Node( |
| 447 | + Function( |
| 448 | + input_names=["in_file"], |
| 449 | + output_names=["out_file"], |
| 450 | + function=estimate_reference_image, |
| 451 | + ), |
| 452 | + name=f"func_get_fmriprep_ref_{pipe_num}", |
| 453 | + ) |
433 | 454 |
|
434 | | - node, out = strat_pool.get_data("desc-reorient_bold") |
435 | | - wf.connect(node, out, func_get_RPI, "in_file") |
| 455 | + node, out = strat_pool.get_data("desc-reorient_bold") |
| 456 | + wf.connect(node, out, func_get_RPI, "in_file") |
436 | 457 |
|
437 | 458 | outputs = {"motion-basefile": (func_get_RPI, "out_file")} |
438 | 459 |
|
439 | | - return (wf, outputs) |
| 460 | + return wf, outputs |
440 | 461 |
|
441 | 462 |
|
442 | 463 | def motion_correct_3dvolreg(wf, cfg, strat_pool, pipe_num): |
@@ -728,7 +749,9 @@ def motion_correct_mcflirt(wf, cfg, strat_pool, pipe_num): |
728 | 749 | } |
729 | 750 |
|
730 | 751 |
|
731 | | -def motion_correct_connections(wf, cfg, strat_pool, pipe_num, opt): |
| 752 | +def motion_correct_connections( |
| 753 | + wf, cfg, strat_pool, pipe_num, opt |
| 754 | +): # -> tuple[Any, dict[str, tuple[Node, str]]]: |
732 | 755 | """Check opt for valid option, then connect that option.""" |
733 | 756 | motion_correct_options = valid_options["motion_correction"] |
734 | 757 | if opt not in motion_correct_options: |
|
0 commit comments