From b9d8c1526b98d9c96100fee4aeaca048d8ec588a Mon Sep 17 00:00:00 2001 From: "birajstha:construction_worker::penguin" Date: Mon, 3 Feb 2025 13:04:16 -0500 Subject: [PATCH 1/6] =?UTF-8?q?=E2=9C=A8Introduced=20desc-head=5Fbold=20an?= =?UTF-8?q?d=20changed=20sbref=20generating=20nodeblock?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 3 +++ CPAC/func_preproc/func_preproc.py | 9 +++++-- CPAC/pipeline/schema.py | 5 +++- CPAC/registration/registration.py | 25 ++++++++++++++++--- .../configs/pipeline_config_blank.yml | 2 ++ 5 files changed, 37 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd1205f6b..07192d902 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 `Selected Functional Volume` in functional registration. +- New resource `desc-head_bold` as non skull-stripped bold from nodeblock `bold_masking`. ### Changed @@ -35,6 +37,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 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/schema.py b/CPAC/pipeline/schema.py index cdb72747d..a423aab90 100644 --- a/CPAC/pipeline/schema.py +++ b/CPAC/pipeline/schema.py @@ -741,7 +741,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..d5fc68aa2 100644 --- a/CPAC/registration/registration.py +++ b/CPAC/registration/registration.py @@ -3134,7 +3134,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", ["desc-head_bold", "bold"], "sbref")], outputs=["sbref"], ) def coregistration_prep_vol(wf, cfg, strat_pool, pipe_num, opt=None): @@ -3152,15 +3152,32 @@ def coregistration_prep_vol(wf, cfg, strat_pool, pipe_num, opt=None): if not cfg.registration_workflows["functional_registration"]["coregistration"][ "func_input_prep" ]["reg_with_skull"]: - node, out = strat_pool.get_data("desc-brain_bold") + node, out = strat_pool.get_data("desc-preproc_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-head_bold", "bold"]) wf.connect(node, out, get_func_volume, "in_file_a") - coreg_input = (get_func_volume, "out_file") + if cfg.registration_workflows["functional_registration"]["coregistration"][ + "func_input_prep" + ]["Selected Functional Volume"]["mask_sbref"] and strat_pool.check_rpool( + "space-bold_desc-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" + + wf.connect(get_func_volume, "out_file", 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") + + coreg_input = (mask_sbref, "out_file") + + else: + coreg_input = (get_func_volume, "out_file") outputs = {"sbref": coreg_input} diff --git a/CPAC/resources/configs/pipeline_config_blank.yml b/CPAC/resources/configs/pipeline_config_blank.yml index 5b7f3f518..3c568611f 100644 --- a/CPAC/resources/configs/pipeline_config_blank.yml +++ b/CPAC/resources/configs/pipeline_config_blank.yml @@ -724,6 +724,8 @@ 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_sbref: true + boundary_based_registration: # this is a fork point From cc38711bc528283300d5188909df6da9ad6112cd Mon Sep 17 00:00:00 2001 From: "birajstha:construction_worker::penguin" Date: Mon, 10 Mar 2025 16:31:19 -0400 Subject: [PATCH 2/6] precommit fixes --- CHANGELOG.md | 2 +- CPAC/pipeline/schema.py | 2 +- CPAC/registration/registration.py | 53 ++++++++++++------- .../configs/pipeline_config_blank.yml | 3 +- 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07192d902..5aff2f30d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,7 @@ 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 `Selected Functional Volume` in functional registration. +- New switch `mask_sbref` under `func_input_prep` in functional registration. - New resource `desc-head_bold` as non skull-stripped bold from nodeblock `bold_masking`. ### Changed diff --git a/CPAC/pipeline/schema.py b/CPAC/pipeline/schema.py index a423aab90..eb09c94c9 100644 --- a/CPAC/pipeline/schema.py +++ b/CPAC/pipeline/schema.py @@ -743,8 +743,8 @@ def sanitize(filename): "Mean Functional": {"n4_correct_func": bool1_1}, "Selected Functional Volume": { "func_reg_input_volume": int, - "mask_sbref": bool1_1, }, + "mask_sbref": bool1_1, }, "boundary_based_registration": { "run": forkable, diff --git a/CPAC/registration/registration.py b/CPAC/registration/registration.py index d5fc68aa2..a0e43c150 100644 --- a/CPAC/registration/registration.py +++ b/CPAC/registration/registration.py @@ -3123,6 +3123,40 @@ 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", + "run", + ], + ], + 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"], @@ -3160,24 +3194,7 @@ def coregistration_prep_vol(wf, cfg, strat_pool, pipe_num, opt=None): wf.connect(node, out, get_func_volume, "in_file_a") - if cfg.registration_workflows["functional_registration"]["coregistration"][ - "func_input_prep" - ]["Selected Functional Volume"]["mask_sbref"] and strat_pool.check_rpool( - "space-bold_desc-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" - - wf.connect(get_func_volume, "out_file", 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") - - coreg_input = (mask_sbref, "out_file") - - else: - coreg_input = (get_func_volume, "out_file") + coreg_input = (get_func_volume, "out_file") outputs = {"sbref": coreg_input} diff --git a/CPAC/resources/configs/pipeline_config_blank.yml b/CPAC/resources/configs/pipeline_config_blank.yml index 3c568611f..fee7d4677 100644 --- a/CPAC/resources/configs/pipeline_config_blank.yml +++ b/CPAC/resources/configs/pipeline_config_blank.yml @@ -724,7 +724,8 @@ 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_sbref: true + # Independent of the above `reg_with_skull` option + mask_sbref: On boundary_based_registration: From 83fad00563eefa0c6e48f800243d6d7c0a1f4dcc Mon Sep 17 00:00:00 2001 From: "birajstha:construction_worker::penguin" Date: Mon, 10 Mar 2025 16:50:05 -0400 Subject: [PATCH 3/6] making mask_sbref default off --- CPAC/resources/configs/pipeline_config_blank.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CPAC/resources/configs/pipeline_config_blank.yml b/CPAC/resources/configs/pipeline_config_blank.yml index fee7d4677..212387464 100644 --- a/CPAC/resources/configs/pipeline_config_blank.yml +++ b/CPAC/resources/configs/pipeline_config_blank.yml @@ -725,7 +725,7 @@ registration_workflows: func_reg_input_volume: 0 # Independent of the above `reg_with_skull` option - mask_sbref: On + mask_sbref: Off boundary_based_registration: From 72a91d0e58d728598a795c9ad53cd5f3f3d67786 Mon Sep 17 00:00:00 2001 From: "birajstha:construction_worker::penguin" Date: Mon, 10 Mar 2025 17:07:56 -0400 Subject: [PATCH 4/6] precommit changes --- CPAC/pipeline/cpac_pipeline.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CPAC/pipeline/cpac_pipeline.py b/CPAC/pipeline/cpac_pipeline.py index 26f67c970..c237b59ff 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, @@ -1287,6 +1288,7 @@ def build_workflow(subject_id, sub_dict, cfg, pipeline_name=None): coregistration_prep_vol, coregistration_prep_mean, coregistration_prep_fmriprep, + mask_sbref, ], ] From fd65fb505b308dbf825d77fd4d21a3b45a328116 Mon Sep 17 00:00:00 2001 From: "birajstha:construction_worker::penguin" Date: Mon, 10 Mar 2025 18:20:20 -0400 Subject: [PATCH 5/6] correcting the switch for mask_sbref --- CPAC/registration/registration.py | 1 - 1 file changed, 1 deletion(-) diff --git a/CPAC/registration/registration.py b/CPAC/registration/registration.py index a0e43c150..b8f69b31f 100644 --- a/CPAC/registration/registration.py +++ b/CPAC/registration/registration.py @@ -3133,7 +3133,6 @@ def overwrite_transform_anat_to_template(wf, cfg, strat_pool, pipe_num, opt=None "coregistration", "func_input_prep", "mask_sbref", - "run", ], ], inputs=["sbref", "space-bold_desc-brain_mask"], From e497d62b930f48dbbd95df9edda6dfc237b426ea Mon Sep 17 00:00:00 2001 From: "birajstha:construction_worker::penguin" Date: Fri, 14 Mar 2025 17:42:58 -0400 Subject: [PATCH 6/6] adding changes suggested --- CHANGELOG.md | 6 ++++-- CPAC/pipeline/cpac_pipeline.py | 2 +- CPAC/pipeline/schema.py | 2 -- CPAC/registration/registration.py | 11 ++--------- .../configs/pipeline_config_abcd-options.yml | 3 --- CPAC/resources/configs/pipeline_config_blank.yml | 10 +++------- CPAC/resources/configs/pipeline_config_default.yml | 9 ++++----- 7 files changed, 14 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5aff2f30d..fe16ffe03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,7 @@ 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. +- 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`. ### Changed @@ -57,7 +57,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/pipeline/cpac_pipeline.py b/CPAC/pipeline/cpac_pipeline.py index c237b59ff..1b64b286a 100644 --- a/CPAC/pipeline/cpac_pipeline.py +++ b/CPAC/pipeline/cpac_pipeline.py @@ -1288,8 +1288,8 @@ def build_workflow(subject_id, sub_dict, cfg, pipeline_name=None): coregistration_prep_vol, coregistration_prep_mean, coregistration_prep_fmriprep, - mask_sbref, ], + mask_sbref, ] # Distortion/Susceptibility Correction diff --git a/CPAC/pipeline/schema.py b/CPAC/pipeline/schema.py index eb09c94c9..1706547e2 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( { diff --git a/CPAC/registration/registration.py b/CPAC/registration/registration.py index b8f69b31f..015598f75 100644 --- a/CPAC/registration/registration.py +++ b/CPAC/registration/registration.py @@ -3167,7 +3167,7 @@ def mask_sbref(wf, cfg, strat_pool, pipe_num, opt=None): "input", ], option_val="Selected_Functional_Volume", - inputs=[("desc-preproc_bold", ["desc-head_bold", "bold"], "sbref")], + inputs=[("desc-preproc_bold", "sbref")], outputs=["sbref"], ) def coregistration_prep_vol(wf, cfg, strat_pool, pipe_num, opt=None): @@ -3182,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-preproc_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-head_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 212387464..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,8 +721,8 @@ 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 - # Independent of the above `reg_with_skull` option - mask_sbref: Off + # Mask the sbref created by coregistration input prep nodeblocks above before registration + mask_sbref: On boundary_based_registration: @@ -755,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