Skip to content

Commit b0c8c98

Browse files
authored
Merge pull request #1926 from e-kenneally/fix/fs_ingress
🐛 Fix bug in abcd-options workflow
2 parents 18dfabe + 2c1b3db commit b0c8c98

File tree

8 files changed

+53
-123
lines changed

8 files changed

+53
-123
lines changed

CPAC/anat_preproc/anat_preproc.py

Lines changed: 30 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -914,33 +914,43 @@ def freesurfer_abcd_brain_connector(wf, cfg, strat_pool, pipe_num, opt):
914914
### ABCD harmonization - anatomical brain mask generation ###
915915
# Ref: https://github.com/DCAN-Labs/DCAN-HCP/blob/master/PostFreeSurfer/PostFreeSurferPipeline.sh#L151-L156
916916

917-
wmparc_to_native = pe.Node(
918-
interface=freesurfer.ApplyVolTransform(),
919-
name='wmparc_to_native')
920917

921-
wmparc_to_native.inputs.reg_header = True
922-
923-
node, out = strat_pool.get_data('pipeline-fs_wmparc')
924-
wf.connect(node, out, wmparc_to_native, 'source_file')
925-
926-
node, out = strat_pool.get_data('pipeline-fs_raw-average')
927-
wf.connect(node, out, wmparc_to_native, 'target_file')
928-
929-
node, out = strat_pool.get_data('pipeline-fs_xfm')
930-
wf.connect(node, out, wmparc_to_native, 'xfm_reg_file')
931-
932-
node, out = strat_pool.get_data('freesurfer-subject-dir')
933-
934-
wf.connect(node, out, wmparc_to_native, 'subjects_dir')
935918
wmparc_to_nifti = pe.Node(util.Function(input_names=['in_file',
936919
'reslice_like',
937920
'args'],
938921
output_names=['out_file'],
939922
function=mri_convert),
940923
name=f'wmparc_to_nifti_{pipe_num}')
941-
wmparc_to_nifti.inputs.args = '-rt nearest'
924+
925+
# Register wmparc file if ingressing FreeSurfer data
926+
if strat_pool.check_rpool('pipeline-fs_xfm'):
927+
928+
wmparc_to_native = pe.Node(
929+
interface=freesurfer.ApplyVolTransform(),
930+
name='wmparc_to_native')
931+
932+
wmparc_to_native.inputs.reg_header = True
933+
934+
node, out = strat_pool.get_data('pipeline-fs_wmparc')
935+
wf.connect(node, out, wmparc_to_native, 'source_file')
936+
937+
node, out = strat_pool.get_data('pipeline-fs_raw-average')
938+
wf.connect(node, out, wmparc_to_native, 'target_file')
939+
940+
node, out = strat_pool.get_data('pipeline-fs_xfm')
941+
wf.connect(node, out, wmparc_to_native, 'xfm_reg_file')
942+
943+
node, out = strat_pool.get_data('freesurfer-subject-dir')
944+
wf.connect(node, out, wmparc_to_native, 'subjects_dir')
945+
946+
wf.connect(wmparc_to_native, 'transformed_file', wmparc_to_nifti, 'in_file')
947+
948+
else:
949+
950+
node, out = strat_pool.get_data('pipeline-fs_wmparc')
951+
wf.connect(node, out, wmparc_to_nifti, 'in_file')
942952

943-
wf.connect(wmparc_to_native, 'transformed_file', wmparc_to_nifti, 'in_file')
953+
wmparc_to_nifti.inputs.args = '-rt nearest'
944954

945955
node, out = strat_pool.get_data('desc-preproc_T1w')
946956
wf.connect(node, out, wmparc_to_nifti, 'reslice_like')
@@ -2677,53 +2687,13 @@ def freesurfer_abcd_preproc(wf, cfg, strat_pool, pipe_num, opt=None):
26772687
wf.connect(average_brain, 'out_stat',
26782688
normalize_head, 'number')
26792689

2680-
if strat_pool.check_rpool('freesurfer-subject-dir'):
2681-
outputs = {
2690+
outputs = {
26822691
'desc-restore_T1w': (fast_correction, 'outputspec.anat_restore'),
26832692
'desc-restore-brain_T1w': (fast_correction,
26842693
'outputspec.anat_brain_restore'),
26852694
'pipeline-fs_desc-fast_biasfield': (fast_correction, 'outputspec.bias_field')}
2686-
return (wf, outputs)
2687-
2688-
else:
2689-
2690-
### recon-all -all step ###
2691-
reconall = pe.Node(interface=freesurfer.ReconAll(),
2692-
name=f'anat_freesurfer_{pipe_num}',
2693-
mem_gb=2.7)
2694-
2695-
sub_dir = cfg.pipeline_setup['working_directory']['path']
2696-
freesurfer_subject_dir = os.path.join(sub_dir,
2697-
'cpac_'+cfg['subject_id'],
2698-
f'anat_preproc_freesurfer_{pipe_num}',
2699-
'anat_freesurfer')
2700-
2701-
# create the directory for FreeSurfer node
2702-
if not os.path.exists(freesurfer_subject_dir):
2703-
os.makedirs(freesurfer_subject_dir)
2704-
2705-
reconall.inputs.directive = 'all'
2706-
reconall.inputs.subjects_dir = freesurfer_subject_dir
2707-
reconall.inputs.openmp = cfg.pipeline_setup['system_config']['num_OMP_threads']
2708-
2709-
wf.connect(normalize_head, 'out_file',
2710-
reconall, 'T1_files')
2711-
2712-
wf, hemisphere_outputs = freesurfer_hemispheres(wf, reconall, pipe_num)
2713-
2714-
outputs = {
2715-
'desc-restore_T1w': (fast_correction, 'outputspec.anat_restore'),
2716-
'desc-restore-brain_T1w': (fast_correction,
2717-
'outputspec.anat_brain_restore'),
2718-
'pipeline-fs_desc-fast_biasfield': (fast_correction, 'outputspec.bias_field'),
2719-
'pipeline-fs_wmparc': (reconall, 'wmparc'),
2720-
'freesurfer-subject-dir': (reconall, 'subjects_dir'),
2721-
**hemisphere_outputs
2722-
}
2723-
27242695
return (wf, outputs)
27252696

2726-
27272697
# we're grabbing the postproc outputs and appending them to
27282698
# the reconall outputs
27292699
@docstring_parameter(postproc_outputs=str(flatten_list(freesurfer_abcd_preproc, 'outputs')

CPAC/pipeline/cpac_pipeline.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import copy
2424
import faulthandler
2525

26-
from logging import getLogger
26+
from CPAC.utils.monitoring.custom_logging import getLogger
2727
from time import strftime
2828

2929
import nipype
@@ -887,8 +887,7 @@ def build_anat_preproc_stack(rpool, cfg, pipeline_blocks=None):
887887
]
888888
elif cfg.anatomical_preproc['acpc_alignment']['acpc_target'] == 'whole-head':
889889
if (rpool.check_rpool('space-T1w_desc-brain_mask') and \
890-
cfg.anatomical_preproc['acpc_alignment']['align_brain_mask']) or \
891-
cfg.surface_analysis['freesurfer']['run_reconall']:
890+
cfg.anatomical_preproc['acpc_alignment']['align_brain_mask']):
892891
acpc_blocks = [
893892
acpc_align_head_with_mask
894893
# outputs space-T1w_desc-brain_mask for later - keep the mask (the user provided)

CPAC/pipeline/engine.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555

5656
from CPAC.resources.templates.lookup_table import lookup_identifier
5757

58-
logger = logging.getLogger('nipype.workflow')
58+
logger = getLogger('nipype.workflow')
5959
verbose_logger = logging.getLogger('engine')
6060

6161

@@ -448,6 +448,7 @@ def get_strats(self, resources, debug=False):
448448
linked_resources = []
449449
resource_list = []
450450
if debug:
451+
verbose_logger = getLogger('engine')
451452
verbose_logger.debug('\nresources: %s', resources)
452453
for resource in resources:
453454
# grab the linked-input tuples
@@ -471,6 +472,7 @@ def get_strats(self, resources, debug=False):
471472
variant_pool = {}
472473
len_inputs = len(resource_list)
473474
if debug:
475+
verbose_logger = getLogger('engine')
474476
verbose_logger.debug('linked_resources: %s',
475477
linked_resources)
476478
verbose_logger.debug('resource_list: %s', resource_list)
@@ -498,6 +500,7 @@ def get_strats(self, resources, debug=False):
498500
f'NO-{val[0]}')
499501

500502
if debug:
503+
verbose_logger = getLogger('engine')
501504
verbose_logger.debug('%s sub_pool: %s\n', resource, sub_pool)
502505
total_pool.append(sub_pool)
503506

@@ -533,6 +536,7 @@ def get_strats(self, resources, debug=False):
533536
strat_list_list.append(strat_list)
534537

535538
if debug:
539+
verbose_logger = getLogger('engine')
536540
verbose_logger.debug('len(strat_list_list): %s\n',
537541
len(strat_list_list))
538542
for strat_list in strat_list_list:
@@ -1320,11 +1324,11 @@ def connect_block(self, wf, cfg, rpool):
13201324
option_val = option_config[-1]
13211325
if option_val in self.grab_tiered_dct(cfg, key_list[:-1]):
13221326
opts.append(option_val)
1323-
else: # AND, if there are multiple option-val's (in a list) in the docstring, it gets iterated below in 'for opt in option' etc. AND THAT'S WHEN YOU HAVE TO DELINEATE WITHIN THE NODE BLOCK CODE!!!
1327+
else: # AND, if there are multiple option-val's (in a list) in the docstring, it gets iterated below in 'for opt in option' etc. AND THAT'S WHEN YOU HAVE TO DELINEATE WITHIN THE NODE BLOCK CODE!!!
13241328
opts = [None]
13251329
all_opts += opts
1326-
13271330
for name, block_dct in self.node_blocks.items(): # <--- iterates over either the single node block in the sequence, or a list of node blocks within the list of node blocks, i.e. for option forking.
1331+
13281332
switch = self.check_null(block_dct['switch'])
13291333
config = self.check_null(block_dct['config'])
13301334
option_key = self.check_null(block_dct['option_key'])
@@ -1395,7 +1399,6 @@ def connect_block(self, wf, cfg, rpool):
13951399
switch = self.grab_tiered_dct(cfg, key_list)
13961400
if not isinstance(switch, list):
13971401
switch = [switch]
1398-
13991402
if True in switch:
14001403
for pipe_idx, strat_pool in rpool.get_strats(
14011404
inputs, debug).items(): # strat_pool is a ResourcePool like {'desc-preproc_T1w': { 'json': info, 'data': (node, out) }, 'desc-brain_mask': etc.}
@@ -1418,7 +1421,6 @@ def connect_block(self, wf, cfg, rpool):
14181421
input_name = interface[1]
14191422
strat_pool.copy_resource(input_name, interface[0])
14201423
replaced_inputs.append(interface[0])
1421-
14221424
try:
14231425
wf, outs = block_function(wf, cfg, strat_pool,
14241426
pipe_x, opt)
@@ -1441,6 +1443,7 @@ def connect_block(self, wf, cfg, rpool):
14411443
node_name = f'{node_name}_{opt["Name"]}'
14421444

14431445
if debug:
1446+
verbose_logger = getLogger('engine')
14441447
verbose_logger.debug('\n=======================')
14451448
verbose_logger.debug('Node name: %s', node_name)
14461449
prov_dct = \
@@ -1539,7 +1542,6 @@ def connect_block(self, wf, cfg, rpool):
15391542
new_json_info,
15401543
pipe_idx,
15411544
pipe_x)
1542-
15431545
return wf
15441546

15451547

@@ -1736,7 +1738,11 @@ def ingress_raw_anat_data(wf, rpool, cfg, data_paths, unique_id, part_id,
17361738
dl_dir=cfg.pipeline_setup['working_directory']['path'])
17371739
rpool.set_data(key, fs_ingress, 'outputspec.data',
17381740
{}, "", f"fs_{key}_ingress")
1739-
1741+
else:
1742+
warnings.warn(str(
1743+
LookupError("\n[!] Path does not exist for "
1744+
f"{fullpath}.\n")))
1745+
17401746
return rpool
17411747

17421748

@@ -1776,6 +1782,7 @@ def ingress_raw_func_data(wf, rpool, cfg, data_paths, unique_id, part_id,
17761782
# pylint: disable=protected-access
17771783
wf._local_func_scans = local_func_scans
17781784
if cfg.pipeline_setup['Debugging']['verbose']:
1785+
verbose_logger = getLogger('engine')
17791786
verbose_logger.debug('local_func_scans: %s', local_func_scans)
17801787
del local_func_scans
17811788

CPAC/resources/configs/pipeline_config_abcd-options.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ surface_analysis:
3636
# Ingress freesurfer recon-all folder
3737
ingress_reconall: On
3838

39-
# FreeSurfer will run as part of configured brain extraction in this specific configuration, so FreeSurfer's independent run was automatically disabled.
40-
run_reconall: Off
39+
run_reconall: On
4140

4241
# Run ABCD-HCP post FreeSurfer and fMRISurface pipeline
4342
post_freesurfer:

CPAC/surface/globals.py

Lines changed: 0 additions & 5 deletions
This file was deleted.

CPAC/surface/surf_preproc.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from logging import raiseExceptions
2+
from CPAC.utils.monitoring.custom_logging import log_subprocess
23
import os
34
import nipype.interfaces.utility as util
45
from CPAC.utils.interfaces.function import Function
@@ -37,7 +38,6 @@ def run_surface(post_freesurfer_folder,
3738
"""
3839

3940
import os
40-
import subprocess
4141

4242
recon_all_path = os.path.join(freesurfer_folder, 'recon_all')
4343

@@ -54,7 +54,7 @@ def run_surface(post_freesurfer_folder,
5454
'--hiresmesh', high_res_mesh, '--lowresmesh', low_res_mesh, \
5555
'--subcortgraylabels', subcortical_gray_labels, '--freesurferlabels', freesurfer_labels]
5656

57-
subprocess.check_output(cmd)
57+
log_subprocess(cmd)
5858

5959
# DCAN-HCP fMRISurface
6060
# https://github.com/DCAN-Labs/DCAN-HCP/blob/master/fMRISurface/GenericfMRISurfaceProcessingPipeline.sh
@@ -64,7 +64,7 @@ def run_surface(post_freesurfer_folder,
6464
scout_bold, '--lowresmesh', low_res_mesh, '--grayordinatesres',
6565
gray_ordinates_res, '--fmrires', fmri_res, '--smoothingFWHM',
6666
smooth_fwhm]
67-
subprocess.check_output(cmd)
67+
log_subprocess(cmd)
6868

6969
dtseries = os.path.join(post_freesurfer_folder,
7070
'MNINonLinear/Results/task-rest01/'

CPAC/utils/configuration/configuration.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
from warnings import warn
2323
import pkg_resources as p
2424
import yaml
25-
from CPAC.surface.globals import DOUBLERUN_GUARD_MESSAGE
2625
from CPAC.utils.utils import load_preconfig
2726
from .diff import dct_diff
2827

@@ -118,18 +117,6 @@ def __init__(self, config_map=None):
118117
# replace spaces with hyphens in Regressor 'Name's
119118
regressor['Name'] = regressor['Name'].replace(' ', '-')
120119

121-
# Don't double-run FreeSurfer
122-
try:
123-
if 'FreeSurfer-ABCD' in config_map['anatomical_preproc'][
124-
'brain_extraction']['using']:
125-
self.set_nested(config_map,
126-
['surface_analysis', 'freesurfer',
127-
'run_reconall'],
128-
False)
129-
warn(DOUBLERUN_GUARD_MESSAGE)
130-
except (KeyError, TypeError):
131-
pass
132-
133120
config_map = schema(config_map)
134121

135122
# remove 'FROM' before setting attributes now that it's imported

CPAC/utils/configuration/yaml_template.py

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from datetime import datetime
2121
from hashlib import sha1
2222
import yaml
23-
from CPAC.surface.globals import DOUBLERUN_GUARD_MESSAGE
23+
2424
from CPAC.utils.configuration import Configuration, Preconfiguration, \
2525
preconfig_yaml
2626
from CPAC.utils.utils import set_nested_value, update_config_dict, \
@@ -87,18 +87,7 @@ def dump(self, new_dict, parents=None):
8787
-------
8888
str
8989
"""
90-
# Initialize variable for automatically updated value
91-
if parents == ['surface_analysis', 'freesurfer'] or parents is None:
92-
freesurfer_extraction = False
93-
try:
94-
brain_extractions = self.get_nested(
95-
new_dict, ['anatomical_preproc', 'brain_extraction',
96-
'using'])
97-
except KeyError:
98-
brain_extractions = []
99-
if (brain_extractions is not None and
100-
'FreeSurfer-ABCD' in brain_extractions):
101-
freesurfer_extraction = True
90+
10291
# SSOT FSLDIR
10392
try: # Get from current config
10493
fsldir = self.get_nested(new_dict,
@@ -117,17 +106,6 @@ def dump(self, new_dict, parents=None):
117106
_dump = ['%YAML 1.1', '---']
118107
if 'pipeline_setup' not in new_dict:
119108
new_dict['pipeline_setup'] = None
120-
# Insert automatically-changed value in original dict
121-
if freesurfer_extraction:
122-
new_dict = set_nested_value(
123-
new_dict, ['surface_analysis', 'freesurfer',
124-
'run_reconall'], False)
125-
ingress_keys = ['surface_analysis', 'freesurfer', 'ingress_reconall']
126-
try:
127-
self.get_nested(new_dict, ingress_keys)
128-
except KeyError:
129-
new_dict = set_nested_value(new_dict, ingress_keys,
130-
self.get_nested(self._dict, ingress_keys))
131109
else:
132110
_dump = []
133111
# Prepare for indentation
@@ -150,12 +128,7 @@ def dump(self, new_dict, parents=None):
150128
value = self.get_nested(new_dict, keys)
151129
except KeyError: # exclude unincluded keys
152130
continue
153-
# Add comment for automatically changed value
154-
if (keys == ['surface_analysis', 'freesurfer', 'run_reconall'] and
155-
freesurfer_extraction):
156-
if comment is None:
157-
comment = []
158-
comment.append(f'# {DOUBLERUN_GUARD_MESSAGE}')
131+
159132
# Print comment if there's one above this key in the template
160133
if comment:
161134
if key != 'pipeline_setup':

0 commit comments

Comments
 (0)