diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a6ba9e38..70279cfd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Required positional parameter "wf" in input and output of `ingress_pipeconfig_paths` function, where a node to reorient templates is added to the `wf`. - Required positional parameter "orientation" to `resolve_resolution`. - Optional positional argument "cfg" to `create_lesion_preproc`. +- New switch `mask_sbref` under `func_input_prep` in functional registration and set to default `on`. +- New resource `desc-head_bold` as non skull-stripped bold from nodeblock `bold_masking`. - `censor_file_path` from `offending_timepoints_connector` in the `build_nuisance_regressor` node. ### Changed @@ -37,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Moved `FSL-AFNI subworkflow` from inside a `bold_mask_fsl_afni` nodeblock into a separate function. - Renamed `desc-ref_bold` created in this workflow to `desc-unifized_bold`. - `coregistration_prep_fmriprep` nodeblock now checks if `desc-unifized_bold` exists in the Resource Pool, if not it runs the `FSL-AFNI subworkflow` to create it. +- Input `desc-brain_bold` to `desc-preproc_bold` for `sbref` generation nodeblock `coregistration_prep_vol`. ### Fixed @@ -57,7 +60,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - as output from FNIRT registration. - as inputs from Nodeblocks requesting it and, replaced with `space-template_desc-brain_mask`. - from outputs tsv. - +- Inputs `[desc-motion_bold, bold]` from `coregistration_prep_vol` nodeblock. +- `input` field from `coregistration` in blank and default config. +- `reg_with_skull` swtich from `func_input_prep` in blank and default config. ## [1.8.7] - 2024-05-03 diff --git a/CPAC/func_preproc/func_preproc.py b/CPAC/func_preproc/func_preproc.py index ac3335d8d..602a0d73c 100644 --- a/CPAC/func_preproc/func_preproc.py +++ b/CPAC/func_preproc/func_preproc.py @@ -1740,6 +1740,10 @@ def bold_mask_ccs(wf, cfg, strat_pool, pipe_num, opt=None): "Description": "The skull-stripped BOLD time-series.", "SkullStripped": True, }, + "desc-head_bold": { + "Description": "The non skull-stripped BOLD time-series.", + "SkullStripped": False, + }, }, ) def bold_masking(wf, cfg, strat_pool, pipe_num, opt=None): @@ -1751,8 +1755,8 @@ def bold_masking(wf, cfg, strat_pool, pipe_num, opt=None): func_edge_detect.inputs.expr = "a*b" func_edge_detect.inputs.outputtype = "NIFTI_GZ" - node, out = strat_pool.get_data("desc-preproc_bold") - wf.connect(node, out, func_edge_detect, "in_file_a") + node_head_bold, out_head_bold = strat_pool.get_data("desc-preproc_bold") + wf.connect(node_head_bold, out_head_bold, func_edge_detect, "in_file_a") node, out = strat_pool.get_data("space-bold_desc-brain_mask") wf.connect(node, out, func_edge_detect, "in_file_b") @@ -1760,6 +1764,7 @@ def bold_masking(wf, cfg, strat_pool, pipe_num, opt=None): outputs = { "desc-preproc_bold": (func_edge_detect, "out_file"), "desc-brain_bold": (func_edge_detect, "out_file"), + "desc-head_bold": (node_head_bold, out_head_bold), } return (wf, outputs) diff --git a/CPAC/pipeline/cpac_pipeline.py b/CPAC/pipeline/cpac_pipeline.py index 26f67c970..1b64b286a 100644 --- a/CPAC/pipeline/cpac_pipeline.py +++ b/CPAC/pipeline/cpac_pipeline.py @@ -148,6 +148,7 @@ coregistration_prep_vol, create_func_to_T1template_symmetric_xfm, create_func_to_T1template_xfm, + mask_sbref, overwrite_transform_anat_to_template, register_ANTs_anat_to_template, register_ANTs_EPI_to_template, @@ -1288,6 +1289,7 @@ def build_workflow(subject_id, sub_dict, cfg, pipeline_name=None): coregistration_prep_mean, coregistration_prep_fmriprep, ], + mask_sbref, ] # Distortion/Susceptibility Correction diff --git a/CPAC/pipeline/schema.py b/CPAC/pipeline/schema.py index 459c5e22e..c80172ce4 100644 --- a/CPAC/pipeline/schema.py +++ b/CPAC/pipeline/schema.py @@ -725,12 +725,10 @@ def sanitize(filename): "reference": In({"brain", "restore-brain"}), "interpolation": In({"trilinear", "sinc", "spline"}), "using": str, - "input": str, "cost": str, "dof": int, "arguments": Maybe(str), "func_input_prep": { - "reg_with_skull": bool1_1, "input": [ In( { @@ -741,7 +739,10 @@ def sanitize(filename): ) ], "Mean Functional": {"n4_correct_func": bool1_1}, - "Selected Functional Volume": {"func_reg_input_volume": int}, + "Selected Functional Volume": { + "func_reg_input_volume": int, + }, + "mask_sbref": bool1_1, }, "boundary_based_registration": { "run": forkable, diff --git a/CPAC/registration/registration.py b/CPAC/registration/registration.py index 8c4a20e60..015598f75 100644 --- a/CPAC/registration/registration.py +++ b/CPAC/registration/registration.py @@ -3123,6 +3123,39 @@ def overwrite_transform_anat_to_template(wf, cfg, strat_pool, pipe_num, opt=None return (wf, outputs) +@nodeblock( + name="mask_sbref", + switch=[ + ["registration_workflows", "functional_registration", "coregistration", "run"], + [ + "registration_workflows", + "functional_registration", + "coregistration", + "func_input_prep", + "mask_sbref", + ], + ], + inputs=["sbref", "space-bold_desc-brain_mask"], + outputs=["sbref"], +) +def mask_sbref(wf, cfg, strat_pool, pipe_num, opt=None): + """Mask sbref with brain mask.""" + mask_sbref = pe.Node(interface=afni.Calc(), name=f"mask_sbref_{pipe_num}") + + mask_sbref.inputs.expr = "a*b" + mask_sbref.inputs.outputtype = "NIFTI_GZ" + + node, out = strat_pool.get_data("sbref") + wf.connect(node, out, mask_sbref, "in_file_a") + + node, out = strat_pool.get_data("space-bold_desc-brain_mask") + wf.connect(node, out, mask_sbref, "in_file_b") + + outputs = {"sbref": (mask_sbref, "out_file")} + + return (wf, outputs) + + @nodeblock( name="coregistration_prep_vol", switch=["functional_preproc", "run"], @@ -3134,7 +3167,7 @@ def overwrite_transform_anat_to_template(wf, cfg, strat_pool, pipe_num, opt=None "input", ], option_val="Selected_Functional_Volume", - inputs=[("desc-brain_bold", ["desc-motion_bold", "bold"], "sbref")], + inputs=[("desc-preproc_bold", "sbref")], outputs=["sbref"], ) def coregistration_prep_vol(wf, cfg, strat_pool, pipe_num, opt=None): @@ -3149,14 +3182,7 @@ def coregistration_prep_vol(wf, cfg, strat_pool, pipe_num, opt=None): outputtype="NIFTI_GZ", ) - if not cfg.registration_workflows["functional_registration"]["coregistration"][ - "func_input_prep" - ]["reg_with_skull"]: - node, out = strat_pool.get_data("desc-brain_bold") - else: - # TODO check which file is functional_skull_leaf - # TODO add a function to choose brain or skull? - node, out = strat_pool.get_data(["desc-motion_bold", "bold"]) + node, out = strat_pool.get_data("desc-preproc_bold") wf.connect(node, out, get_func_volume, "in_file_a") diff --git a/CPAC/resources/configs/pipeline_config_abcd-options.yml b/CPAC/resources/configs/pipeline_config_abcd-options.yml index 937ab7a63..714a30189 100644 --- a/CPAC/resources/configs/pipeline_config_abcd-options.yml +++ b/CPAC/resources/configs/pipeline_config_abcd-options.yml @@ -199,9 +199,6 @@ registration_workflows: run: On func_input_prep: - # Choose whether to use functional brain or skull as the input to functional-to-anatomical registration - reg_with_skull: On - # Choose whether to use the mean of the functional/EPI as the input to functional-to-anatomical registration or one of the volumes from the functional 4D timeseries that you choose. # input: ['Mean_Functional', 'Selected_Functional_Volume', 'fmriprep_reference'] input: [Selected_Functional_Volume] diff --git a/CPAC/resources/configs/pipeline_config_blank.yml b/CPAC/resources/configs/pipeline_config_blank.yml index 5b7f3f518..2ad2a5356 100644 --- a/CPAC/resources/configs/pipeline_config_blank.yml +++ b/CPAC/resources/configs/pipeline_config_blank.yml @@ -706,9 +706,6 @@ registration_workflows: run: Off func_input_prep: - # Choose whether to use functional brain or skull as the input to functional-to-anatomical registration - reg_with_skull: Off - # Choose whether to use the mean of the functional/EPI as the input to functional-to-anatomical registration or one of the volumes from the functional 4D timeseries that you choose. # input: ['Mean_Functional', 'Selected_Functional_Volume', 'fmriprep_reference'] input: [Mean_Functional] @@ -724,6 +721,9 @@ registration_workflows: #Input the index of which volume from the functional 4D timeseries input file you wish to use as the input for functional-to-anatomical registration. func_reg_input_volume: 0 + # Mask the sbref created by coregistration input prep nodeblocks above before registration + mask_sbref: On + boundary_based_registration: # this is a fork point @@ -752,8 +752,7 @@ registration_workflows: # Choose FSL or ABCD as coregistration method using: FSL - # Choose brain or whole-head as coregistration input - input: brain + #TODO Add input field here to choose between whole head or brain # Choose coregistration interpolation interpolation: trilinear diff --git a/CPAC/resources/configs/pipeline_config_default.yml b/CPAC/resources/configs/pipeline_config_default.yml index 3d067fbbc..2699ff6b5 100644 --- a/CPAC/resources/configs/pipeline_config_default.yml +++ b/CPAC/resources/configs/pipeline_config_default.yml @@ -766,8 +766,7 @@ registration_workflows: # Choose FSL or ABCD as coregistration method using: FSL - # Choose brain or whole-head as coregistration input - input: brain + #TODO Add input field here to choose between whole head or brain # Choose coregistration interpolation interpolation: trilinear @@ -783,9 +782,6 @@ registration_workflows: func_input_prep: - # Choose whether to use functional brain or skull as the input to functional-to-anatomical registration - reg_with_skull: Off - # Choose whether to use the mean of the functional/EPI as the input to functional-to-anatomical registration or one of the volumes from the functional 4D timeseries that you choose. # input: ['Mean_Functional', 'Selected_Functional_Volume', 'fmriprep_reference'] input: ['Mean_Functional'] @@ -802,6 +798,9 @@ registration_workflows: #Input the index of which volume from the functional 4D timeseries input file you wish to use as the input for functional-to-anatomical registration. func_reg_input_volume: 0 + # Mask the sbref created by coregistration input prep nodeblocks above before registration + mask_sbref: On + boundary_based_registration: # this is a fork point # run: [On, Off] - this will run both and fork the pipeline