Skip to content

File tree

15 files changed

+83
-43
lines changed

15 files changed

+83
-43
lines changed
 

‎CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2020

2121
- `pyproject.toml` file with `[build-system]` defined.
2222
- [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/FCP-INDI/C-PAC/main.svg)](https://results.pre-commit.ci/latest/github/FCP-INDI/C-PAC/main) badge to [`README`](./README.md).
23+
- `desired_orientation` key in participant-level pipeline config under `pipeline_setup`.
24+
- Required positional parameter "wf" in input and output of `ingress_pipeconfig_paths` function, where a node to reorient templates is added to the `wf`.
25+
- Required positional parameter "orientation" to `resolve_resolution`.
26+
- Optional positional argument "cfg" to `create_lesion_preproc`.
2327

2428
### Changed
2529

2630
- Moved `pygraphviz` from requirements to `graphviz` optional dependencies group.
2731
- Automatically tag untagged `subject_id` and `unique_id` as `!!str` when loading data config files.
32+
- Made orientation configurable (was hard-coded as "RPI").
2833

2934
### Fixed
3035

‎CPAC/anat_preproc/anat_preproc.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -1233,7 +1233,7 @@ def freesurfer_fsl_brain_connector(wf, cfg, strat_pool, pipe_num, opt):
12331233
mem_gb=0,
12341234
mem_x=(0.0115, "in_file", "t"),
12351235
)
1236-
reorient_fs_brainmask.inputs.orientation = "RPI"
1236+
reorient_fs_brainmask.inputs.orientation = cfg.pipeline_setup["desired_orientation"]
12371237
reorient_fs_brainmask.inputs.outputtype = "NIFTI_GZ"
12381238

12391239
wf.connect(
@@ -1255,7 +1255,7 @@ def freesurfer_fsl_brain_connector(wf, cfg, strat_pool, pipe_num, opt):
12551255
mem_gb=0,
12561256
mem_x=(0.0115, "in_file", "t"),
12571257
)
1258-
reorient_fs_T1.inputs.orientation = "RPI"
1258+
reorient_fs_T1.inputs.orientation = cfg.pipeline_setup["desired_orientation"]
12591259
reorient_fs_T1.inputs.outputtype = "NIFTI_GZ"
12601260

12611261
wf.connect(convert_fs_T1_to_nifti, "out_file", reorient_fs_T1, "in_file")
@@ -1460,7 +1460,7 @@ def anatomical_init(wf, cfg, strat_pool, pipe_num, opt=None):
14601460
mem_gb=0,
14611461
mem_x=(0.0115, "in_file", "t"),
14621462
)
1463-
anat_reorient.inputs.orientation = "RPI"
1463+
anat_reorient.inputs.orientation = cfg.pipeline_setup["desired_orientation"]
14641464
anat_reorient.inputs.outputtype = "NIFTI_GZ"
14651465

14661466
wf.connect(anat_deoblique, "out_file", anat_reorient, "in_file")
@@ -2268,7 +2268,7 @@ def anatomical_init_T2(wf, cfg, strat_pool, pipe_num, opt=None):
22682268
mem_gb=0,
22692269
mem_x=(0.0115, "in_file", "t"),
22702270
)
2271-
T2_reorient.inputs.orientation = "RPI"
2271+
T2_reorient.inputs.orientation = cfg.pipeline_setup["desired_orientation"]
22722272
T2_reorient.inputs.outputtype = "NIFTI_GZ"
22732273

22742274
wf.connect(T2_deoblique, "out_file", T2_reorient, "in_file")

‎CPAC/anat_preproc/lesion_preproc.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def inverse_lesion(lesion_path):
5858
return lesion_out
5959

6060

61-
def create_lesion_preproc(wf_name="lesion_preproc"):
61+
def create_lesion_preproc(cfg=None, wf_name="lesion_preproc"):
6262
"""Process lesions masks.
6363
6464
Lesion mask file is deobliqued and reoriented in the same way as the T1 in
@@ -133,7 +133,9 @@ def create_lesion_preproc(wf_name="lesion_preproc"):
133133
mem_x=(0.0115, "in_file", "t"),
134134
)
135135

136-
lesion_reorient.inputs.orientation = "RPI"
136+
lesion_reorient.inputs.orientation = (
137+
cfg.pipeline_setup["desired_orientation"] if cfg else "RPI"
138+
)
137139
lesion_reorient.inputs.outputtype = "NIFTI_GZ"
138140

139141
preproc.connect(lesion_deoblique, "out_file", lesion_reorient, "in_file")

‎CPAC/func_preproc/func_preproc.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ def func_reorient(wf, cfg, strat_pool, pipe_num, opt=None):
528528
mem_x=(0.0115, "in_file", "t"),
529529
)
530530

531-
func_reorient.inputs.orientation = "RPI"
531+
func_reorient.inputs.orientation = cfg.pipeline_setup["desired_orientation"]
532532
func_reorient.inputs.outputtype = "NIFTI_GZ"
533533

534534
wf.connect(func_deoblique, "out_file", func_reorient, "in_file")
@@ -1290,7 +1290,7 @@ def bold_mask_anatomical_refined(wf, cfg, strat_pool, pipe_num, opt=None):
12901290
mem_x=(0.0115, "in_file", "t"),
12911291
)
12921292

1293-
func_reorient.inputs.orientation = "RPI"
1293+
func_reorient.inputs.orientation = cfg.pipeline_setup["desired_orientation"]
12941294
func_reorient.inputs.outputtype = "NIFTI_GZ"
12951295

12961296
wf.connect(func_deoblique, "out_file", func_reorient, "in_file")

‎CPAC/longitudinal_pipeline/longitudinal_workflow.py

+1
Original file line numberDiff line numberDiff line change
@@ -1204,6 +1204,7 @@ def func_longitudinal_template_wf(subject_id, strat_list, config):
12041204
resampled_template.inputs.template = template
12051205
resampled_template.inputs.template_name = template_name
12061206
resampled_template.inputs.tag = tag
1207+
resampled_template.inputs.orientation = config["desired_orientation"]
12071208

12081209
strat_init.update_resource_pool(
12091210
{template_name: (resampled_template, "resampled_template")}

‎CPAC/pipeline/engine.py

+48-27
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import warnings
2626

2727
from nipype import config, logging
28+
from nipype.interfaces import afni
2829
from nipype.interfaces.utility import Rename
2930

3031
from CPAC.image_utils.spatial_smoothing import spatial_smoothing
@@ -35,7 +36,11 @@
3536
from CPAC.pipeline import nipype_pipeline_engine as pe
3637
from CPAC.pipeline.check_outputs import ExpectedOutputs
3738
from CPAC.pipeline.nodeblock import NodeBlockFunction
38-
from CPAC.pipeline.utils import MOVEMENT_FILTER_KEYS, name_fork, source_set
39+
from CPAC.pipeline.utils import (
40+
MOVEMENT_FILTER_KEYS,
41+
name_fork,
42+
source_set,
43+
)
3944
from CPAC.registration.registration import transform_derivative
4045
from CPAC.resources.templates.lookup_table import lookup_identifier
4146
from CPAC.utils.bids_utils import res_in_filename
@@ -2403,7 +2408,7 @@ def strip_template(data_label, dir_path, filename):
24032408
return data_label, json
24042409

24052410

2406-
def ingress_pipeconfig_paths(cfg, rpool, unique_id, creds_path=None):
2411+
def ingress_pipeconfig_paths(wf, cfg, rpool, unique_id, creds_path=None):
24072412
# ingress config file paths
24082413
# TODO: may want to change the resource keys for each to include one level up in the YAML as well
24092414

@@ -2412,6 +2417,7 @@ def ingress_pipeconfig_paths(cfg, rpool, unique_id, creds_path=None):
24122417

24132418
template_csv = p.resource_filename("CPAC", "resources/cpac_templates.csv")
24142419
template_df = pd.read_csv(template_csv, keep_default_na=False)
2420+
desired_orientation = cfg.pipeline_setup["desired_orientation"]
24152421

24162422
for row in template_df.itertuples():
24172423
key = row.Key
@@ -2468,32 +2474,29 @@ def ingress_pipeconfig_paths(cfg, rpool, unique_id, creds_path=None):
24682474

24692475
resampled_template = pe.Node(
24702476
Function(
2471-
input_names=["resolution", "template", "template_name", "tag"],
2477+
input_names=[
2478+
"orientation",
2479+
"resolution",
2480+
"template",
2481+
"template_name",
2482+
"tag",
2483+
],
24722484
output_names=["resampled_template"],
24732485
function=resolve_resolution,
24742486
as_module=True,
24752487
),
24762488
name="resampled_" + key,
24772489
)
24782490

2491+
resampled_template.inputs.orientation = desired_orientation
24792492
resampled_template.inputs.resolution = resolution
24802493
resampled_template.inputs.template = val
24812494
resampled_template.inputs.template_name = key
24822495
resampled_template.inputs.tag = tag
24832496

2484-
# the set_data below is set up a little differently, because we are
2485-
# injecting and also over-writing already-existing entries
2486-
# other alternative would have been to ingress into the
2487-
# resampled_template node from the already existing entries, but we
2488-
# didn't do that here
2489-
rpool.set_data(
2490-
key,
2491-
resampled_template,
2492-
"resampled_template",
2493-
json_info,
2494-
"",
2495-
"template_resample",
2496-
) # pipe_idx (after the blank json {}) should be the previous strat that you want deleted! because you're not connecting this the regular way, you have to do it manually
2497+
node = resampled_template
2498+
output = "resampled_template"
2499+
node_name = "template_resample"
24972500

24982501
elif val:
24992502
config_ingress = create_general_datasource(f"gather_{key}")
@@ -2503,14 +2506,33 @@ def ingress_pipeconfig_paths(cfg, rpool, unique_id, creds_path=None):
25032506
creds_path=creds_path,
25042507
dl_dir=cfg.pipeline_setup["working_directory"]["path"],
25052508
)
2506-
rpool.set_data(
2507-
key,
2508-
config_ingress,
2509-
"outputspec.data",
2510-
json_info,
2511-
"",
2512-
f"{key}_config_ingress",
2513-
)
2509+
node = config_ingress
2510+
output = "outputspec.data"
2511+
node_name = f"{key}_config_ingress"
2512+
2513+
if val.endswith(".nii" or ".nii.gz"):
2514+
check_reorient = pe.Node(
2515+
interface=afni.Resample(),
2516+
name=f"reorient_{key}",
2517+
)
2518+
2519+
check_reorient.inputs.orientation = desired_orientation
2520+
check_reorient.inputs.outputtype = "NIFTI_GZ"
2521+
2522+
wf.connect(node, output, check_reorient, "in_file")
2523+
node = check_reorient
2524+
output = "out_file"
2525+
node_name = f"{key}_reorient"
2526+
2527+
rpool.set_data(
2528+
key,
2529+
node,
2530+
output,
2531+
json_info,
2532+
"",
2533+
node_name,
2534+
)
2535+
25142536
# templates, resampling from config
25152537
"""
25162538
template_keys = [
@@ -2596,8 +2618,7 @@ def _set_nested(attr, keys):
25962618
)
25972619
cfg.set_nested(cfg, key, node)
25982620
"""
2599-
2600-
return rpool
2621+
return wf, rpool
26012622

26022623

26032624
def initiate_rpool(wf, cfg, data_paths=None, part_id=None):
@@ -2668,7 +2689,7 @@ def initiate_rpool(wf, cfg, data_paths=None, part_id=None):
26682689
)
26692690

26702691
# grab any file paths from the pipeline config YAML
2671-
rpool = ingress_pipeconfig_paths(cfg, rpool, unique_id, creds_path)
2692+
wf, rpool = ingress_pipeconfig_paths(wf, cfg, rpool, unique_id, creds_path)
26722693

26732694
# output files with 4 different scans
26742695

‎CPAC/pipeline/schema.py

+3
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,9 @@ def sanitize(filename):
423423
"skip env check": Maybe(bool), # flag for skipping an environment check
424424
"pipeline_setup": {
425425
"pipeline_name": All(str, Length(min=1), sanitize),
426+
"desired_orientation": In(
427+
{"RPI", "LPI", "RAI", "LAI", "RAS", "LAS", "RPS", "LPS"}
428+
),
426429
"output_directory": {
427430
"path": str,
428431
"source_outputs_dir": Maybe(str),

‎CPAC/pipeline/test/test_engine.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def test_ingress_pipeconfig_data(pipe_config, bids_dir, test_dir):
9090

9191
rpool = ResourcePool(name=unique_id, cfg=cfg)
9292

93-
rpool = ingress_pipeconfig_paths(cfg, rpool, sub_data_dct, unique_id)
93+
wf, rpool = ingress_pipeconfig_paths(wf, cfg, rpool, sub_data_dct, unique_id)
9494

9595
rpool.gather_pipes(wf, cfg, all=True)
9696

‎CPAC/registration/registration.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1736,7 +1736,7 @@ def ANTs_registration_connector(
17361736
"ANTs"
17371737
]["use_lesion_mask"]:
17381738
# Create lesion preproc node to apply afni Refit and Resample
1739-
lesion_preproc = create_lesion_preproc(wf_name=f"lesion_preproc{symm}")
1739+
lesion_preproc = create_lesion_preproc(cfg, wf_name=f"lesion_preproc{symm}")
17401740
wf.connect(inputNode, "lesion_mask", lesion_preproc, "inputspec.lesion")
17411741
wf.connect(
17421742
lesion_preproc,

‎CPAC/registration/tests/mocks.py

+1
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ def configuration_strategy_mock(method="FSL"):
151151
resampled_template.inputs.template = template
152152
resampled_template.inputs.template_name = template_name
153153
resampled_template.inputs.tag = tag
154+
resampled_template.inputs.orientation = "RPI"
154155

155156
strat.update_resource_pool(
156157
{template_name: (resampled_template, "resampled_template")}

‎CPAC/registration/tests/test_registration.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def test_registration_lesion():
130130

131131
anat_preproc.inputs.inputspec.anat = anat_file
132132

133-
lesion_preproc = create_lesion_preproc(wf_name="lesion_preproc")
133+
lesion_preproc = create_lesion_preproc(cfg, wf_name="lesion_preproc")
134134

135135
lesion_preproc.inputs.inputspec.lesion = lesion_file
136136

‎CPAC/resources/configs/pipeline_config_blank.yml

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ pipeline_setup:
1111
# Name for this pipeline configuration - useful for identification.
1212
# This string will be sanitized and used in filepaths
1313
pipeline_name: cpac-blank-template
14+
15+
# Desired orientation for the output data. "RPI", "LPI", "RAI", "LAI", "RAS", "LAS", "RPS", "LPS"
16+
desired_orientation: RPI
17+
1418
output_directory:
1519

1620
# Quality control outputs

‎CPAC/resources/tests/test_templates.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import os
2020

2121
import pytest
22+
import nipype.pipeline.engine as pe
2223

2324
from CPAC.pipeline import ALL_PIPELINE_CONFIGS
2425
from CPAC.pipeline.engine import ingress_pipeconfig_paths, ResourcePool
@@ -29,11 +30,11 @@
2930
@pytest.mark.parametrize("pipeline", ALL_PIPELINE_CONFIGS)
3031
def test_packaged_path_exists(pipeline):
3132
"""
32-
Check that all local templates are included in image at at
33-
least one resolution.
33+
Check that all local templates are included in image at atleast one resolution.
3434
"""
35-
rpool = ingress_pipeconfig_paths(
36-
Preconfiguration(pipeline), ResourcePool(), "pytest"
35+
wf = pe.Workflow(name="test")
36+
wf, rpool = ingress_pipeconfig_paths(
37+
wf, Preconfiguration(pipeline), ResourcePool(), "pytest"
3738
)
3839
for resource in rpool.rpool.values():
3940
node = next(iter(resource.values())).get("data")[0]

‎CPAC/utils/datasource.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1156,7 +1156,7 @@ def res_string_to_tuple(resolution):
11561156
return (float(resolution.replace("mm", "")),) * 3
11571157

11581158

1159-
def resolve_resolution(resolution, template, template_name, tag=None):
1159+
def resolve_resolution(orientation, resolution, template, template_name, tag=None):
11601160
"""Resample a template to a given resolution."""
11611161
from nipype.interfaces import afni
11621162

@@ -1203,6 +1203,7 @@ def resolve_resolution(resolution, template, template_name, tag=None):
12031203
resample.inputs.resample_mode = "Cu"
12041204
resample.inputs.in_file = local_path
12051205
resample.base_dir = "."
1206+
resample.inputs.orientation = orientation
12061207

12071208
resampled_template = resample.run()
12081209
local_path = resampled_template.outputs.out_file

‎CPAC/utils/test_mocks.py

+1
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ def configuration_strategy_mock(method="FSL"):
235235
resampled_template.inputs.template = template
236236
resampled_template.inputs.template_name = template_name
237237
resampled_template.inputs.tag = tag
238+
resampled_template.inputs.orientation = "RPI"
238239

239240
strat.update_resource_pool(
240241
{template_name: (resampled_template, "resampled_template")}

0 commit comments

Comments
 (0)
Please sign in to comment.