Skip to content

Commit 960305c

Browse files
authored
Merge branch 'develop' into verbose_debugging_update
2 parents 10a0e95 + 0ff4c44 commit 960305c

20 files changed

+499
-584
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2828
- Added abililty to fork on motion filter
2929
- Added [`sdcflows`](https://www.nipreps.org/sdcflows/2.0/) to CPAC requirements
3030
- Added NodeBlock information to `pypeline.log` when verbose debugging is on
31+
- Added the ability to ingress FreeSurfer data into CPAC
32+
- Added the ability to toggle FreeSurfer derived masks for brain extraction
3133

3234
### Changed
3335
- Freesurfer output directory ingress moved to the data configuration YAML

CPAC/anat_preproc/anat_preproc.py

Lines changed: 219 additions & 366 deletions
Large diffs are not rendered by default.

CPAC/anat_preproc/utils.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -174,22 +174,22 @@ def split_hemi_interface():
174174
for label in splits:
175175
wf.connect(reconall, label, splits[label], 'multi_file')
176176
outputs = {
177-
'hemi-L_desc-surface_curv': (splits['curv'], 'lh'),
178-
'hemi-R_desc-surface_curv': (splits['curv'], 'rh'),
179-
'hemi-L_desc-surfaceMesh_pial': (splits['pial'], 'lh'),
180-
'hemi-R_desc-surfaceMesh_pial': (splits['pial'], 'rh'),
181-
'hemi-L_desc-surfaceMesh_smoothwm': (splits['smoothwm'], 'lh'),
182-
'hemi-R_desc-surfaceMesh_smoothwm': (splits['smoothwm'], 'rh'),
183-
'hemi-L_desc-surfaceMesh_sphere': (splits['sphere'], 'lh'),
184-
'hemi-R_desc-surfaceMesh_sphere': (splits['sphere'], 'rh'),
185-
'hemi-L_desc-surfaceMap_sulc': (splits['sulc'], 'lh'),
186-
'hemi-R_desc-surfaceMap_sulc': (splits['sulc'], 'rh'),
187-
'hemi-L_desc-surfaceMap_thickness': (splits['thickness'], 'lh'),
188-
'hemi-R_desc-surfaceMap_thickness': (splits['thickness'], 'rh'),
189-
'hemi-L_desc-surfaceMap_volume': (splits['volume'], 'lh'),
190-
'hemi-R_desc-surfaceMap_volume': (splits['volume'], 'rh'),
191-
'hemi-L_desc-surfaceMesh_white': (splits['white'], 'lh'),
192-
'hemi-R_desc-surfaceMesh_white': (splits['white'], 'rh')}
177+
'pipeline-fs_hemi-L_desc-surface_curv': (splits['curv'], 'lh'),
178+
'pipeline-fs_hemi-R_desc-surface_curv': (splits['curv'], 'rh'),
179+
'pipeline-fs_hemi-L_desc-surfaceMesh_pial': (splits['pial'], 'lh'),
180+
'pipeline-fs_hemi-R_desc-surfaceMesh_pial': (splits['pial'], 'rh'),
181+
'pipeline-fs_hemi-L_desc-surfaceMesh_smoothwm': (splits['smoothwm'], 'lh'),
182+
'pipeline-fs_hemi-R_desc-surfaceMesh_smoothwm': (splits['smoothwm'], 'rh'),
183+
'pipeline-fs_hemi-L_desc-surfaceMesh_sphere': (splits['sphere'], 'lh'),
184+
'pipeline-fs_hemi-R_desc-surfaceMesh_sphere': (splits['sphere'], 'rh'),
185+
'pipeline-fs_hemi-L_desc-surfaceMap_sulc': (splits['sulc'], 'lh'),
186+
'pipeline-fs_hemi-R_desc-surfaceMap_sulc': (splits['sulc'], 'rh'),
187+
'pipeline-fs_hemi-L_desc-surfaceMap_thickness': (splits['thickness'], 'lh'),
188+
'pipeline-fs_hemi-R_desc-surfaceMap_thickness': (splits['thickness'], 'rh'),
189+
'pipeline-fs_hemi-L_desc-surfaceMap_volume': (splits['volume'], 'lh'),
190+
'pipeline-fs_hemi-R_desc-surfaceMap_volume': (splits['volume'], 'rh'),
191+
'pipeline-fs_hemi-L_desc-surfaceMesh_white': (splits['white'], 'lh'),
192+
'pipeline-fs_hemi-R_desc-surfaceMesh_white': (splits['white'], 'rh')}
193193

194194
return wf, outputs
195195

CPAC/pipeline/cpac_pipeline.py

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

26+
from logging import getLogger
2627
from time import strftime
2728

2829
import nipype
@@ -41,7 +42,6 @@
4142
from CPAC.pipeline.engine import NodeBlock, initiate_rpool
4243
from CPAC.anat_preproc.anat_preproc import (
4344
freesurfer_reconall,
44-
freesurfer_postproc,
4545
freesurfer_abcd_preproc,
4646
anatomical_init,
4747
acpc_align_head,
@@ -81,7 +81,7 @@
8181
brain_mask_T2,
8282
brain_mask_acpc_T2,
8383
brain_extraction_temp_T2,
84-
brain_extraction_T2
84+
brain_extraction_T2,
8585
)
8686

8787
from CPAC.registration.registration import (
@@ -211,10 +211,10 @@
211211

212212
from CPAC.qc.pipeline import create_qc_workflow
213213
from CPAC.qc.xcp import qc_xcp
214+
214215
from CPAC.utils.monitoring import log_nodes_cb, log_nodes_initial, \
215216
LOGTAIL, set_up_logger, \
216217
WARNING_FREESURFER_OFF_WITH_DATA
217-
from CPAC.utils.monitoring.custom_logging import getLogger
218218
from CPAC.utils.monitoring.draw_gantt_chart import resource_report
219219
from CPAC.utils.utils import (
220220
check_config_resources,
@@ -865,40 +865,27 @@ def build_anat_preproc_stack(rpool, cfg, pipeline_blocks=None):
865865
]
866866
pipeline_blocks += anat_init_blocks
867867

868-
if rpool.check_rpool('freesurfer-subject-dir'):
869-
pipeline_blocks += [freesurfer_postproc]
870-
else:
868+
if not rpool.check_rpool('freesurfer-subject-dir'):
871869
pipeline_blocks += [freesurfer_reconall] # includes postproc
872870

873871
if not rpool.check_rpool('desc-preproc_T1w'):
874872

875873
# brain masking for ACPC alignment
876874
if cfg.anatomical_preproc['acpc_alignment']['acpc_target'] == 'brain':
877-
if rpool.check_rpool('space-T1w_desc-brain_mask') or \
878-
cfg.surface_analysis['freesurfer']['run_reconall']:
879-
acpc_blocks = [
880-
brain_extraction_temp,
881-
acpc_align_brain_with_mask
882-
# outputs space-T1w_desc-brain_mask for later - keep the mask (the user provided)
883-
]
884-
acpc_blocks.append(
885-
[brain_mask_acpc_freesurfer_fsl_tight,
886-
brain_mask_acpc_freesurfer_fsl_loose]
887-
)
888-
else:
889875
acpc_blocks = [
890876
[brain_mask_acpc_afni,
891877
brain_mask_acpc_fsl,
892878
brain_mask_acpc_niworkflows_ants,
893879
brain_mask_acpc_unet,
894-
brain_mask_acpc_freesurfer_abcd],
895-
# brain_mask_acpc_freesurfer
896-
# we don't want these masks to be used later
880+
brain_mask_acpc_freesurfer_abcd,
881+
brain_mask_acpc_freesurfer,
882+
brain_mask_acpc_freesurfer_fsl_tight,
883+
brain_mask_acpc_freesurfer_fsl_loose],
884+
acpc_align_brain_with_mask,
897885
brain_extraction_temp,
898886
acpc_align_brain
899887
]
900-
elif cfg.anatomical_preproc['acpc_alignment'][
901-
'acpc_target'] == 'whole-head':
888+
elif cfg.anatomical_preproc['acpc_alignment']['acpc_target'] == 'whole-head':
902889
if (rpool.check_rpool('space-T1w_desc-brain_mask') and \
903890
cfg.anatomical_preproc['acpc_alignment']['align_brain_mask']) or \
904891
cfg.surface_analysis['freesurfer']['run_reconall']:
@@ -910,6 +897,7 @@ def build_anat_preproc_stack(rpool, cfg, pipeline_blocks=None):
910897
acpc_blocks = [
911898
acpc_align_head # does not output nor generate a mask
912899
]
900+
913901

914902
anat_preproc_blocks = [
915903
(non_local_means, ('T1w', ['desc-preproc_T1w',
@@ -927,18 +915,18 @@ def build_anat_preproc_stack(rpool, cfg, pipeline_blocks=None):
927915
pipeline_blocks += [freesurfer_abcd_preproc]
928916

929917
# Anatomical T1 brain masking
930-
if not rpool.check_rpool('space-T1w_desc-brain_mask') or \
931-
cfg.surface_analysis['freesurfer']['run_reconall']:
932-
anat_brain_mask_blocks = [
933-
[brain_mask_afni,
934-
brain_mask_fsl,
935-
brain_mask_niworkflows_ants,
936-
brain_mask_unet,
937-
brain_mask_freesurfer_abcd,
938-
brain_mask_freesurfer_fsl_tight,
939-
brain_mask_freesurfer_fsl_loose]
940-
]
941-
pipeline_blocks += anat_brain_mask_blocks
918+
919+
anat_brain_mask_blocks = [
920+
[brain_mask_afni,
921+
brain_mask_fsl,
922+
brain_mask_niworkflows_ants,
923+
brain_mask_unet,
924+
brain_mask_freesurfer_abcd,
925+
brain_mask_freesurfer,
926+
brain_mask_freesurfer_fsl_tight,
927+
brain_mask_freesurfer_fsl_loose]
928+
]
929+
pipeline_blocks += anat_brain_mask_blocks
942930

943931
# T2w Anatomical Preprocessing
944932
if rpool.check_rpool('T2w'):
@@ -1030,7 +1018,6 @@ def build_T1w_registration_stack(rpool, cfg, pipeline_blocks=None):
10301018
warp_T1mask_to_template
10311019
]
10321020

1033-
10341021
if not rpool.check_rpool('desc-restore-brain_T1w'):
10351022
reg_blocks.append(correct_restore_brain_intensity_abcd)
10361023

@@ -1362,6 +1349,7 @@ def build_workflow(subject_id, sub_dict, cfg, pipeline_name=None,
13621349
apply_func_warp['EPI'] = (_r_w_f_r['coregistration']['run'] and _r_w_f_r['func_registration_to_template']['run_EPI'])
13631350
else:
13641351
apply_func_warp['EPI'] = (_r_w_f_r['func_registration_to_template']['run_EPI'])
1352+
13651353
del _r_w_f_r
13661354

13671355
template_funcs = [
@@ -1393,6 +1381,7 @@ def build_workflow(subject_id, sub_dict, cfg, pipeline_name=None,
13931381

13941382
# PostFreeSurfer and fMRISurface
13951383
if not rpool.check_rpool('space-fsLR_den-32k_bold.dtseries'):
1384+
13961385
pipeline_blocks += [surface_postproc]
13971386

13981387
# Extractions and Derivatives

CPAC/pipeline/engine.py

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import ast
1818
import copy
1919
from itertools import chain
20+
import logging
2021
import os
2122
import re
2223
from types import FunctionType
@@ -54,7 +55,8 @@
5455

5556
from CPAC.resources.templates.lookup_table import lookup_identifier
5657

57-
logger = getLogger('nipype.workflow')
58+
logger = logging.getLogger('nipype.workflow')
59+
verbose_logger = logging.getLogger('engine')
5860

5961

6062
class ResourcePool:
@@ -437,6 +439,7 @@ def flatten_prov(self, prov):
437439
return flat_prov
438440

439441
def get_strats(self, resources, debug=False):
442+
440443
# TODO: NOTE: NOT COMPATIBLE WITH SUB-RPOOL/STRAT_POOLS
441444
# TODO: (and it doesn't have to be)
442445

@@ -445,7 +448,6 @@ def get_strats(self, resources, debug=False):
445448
linked_resources = []
446449
resource_list = []
447450
if debug:
448-
verbose_logger = getLogger('engine')
449451
verbose_logger.debug('\nresources: %s', resources)
450452
for resource in resources:
451453
# grab the linked-input tuples
@@ -469,7 +471,6 @@ def get_strats(self, resources, debug=False):
469471
variant_pool = {}
470472
len_inputs = len(resource_list)
471473
if debug:
472-
verbose_logger = getLogger('engine')
473474
verbose_logger.debug('linked_resources: %s',
474475
linked_resources)
475476
verbose_logger.debug('resource_list: %s', resource_list)
@@ -482,8 +483,7 @@ def get_strats(self, resources, debug=False):
482483
continue
483484
sub_pool = []
484485
if debug:
485-
verbose_logger = getLogger('engine')
486-
verbose_logger.debug('%s len(rp_dct): %s\n', resource, len(rp_dct))
486+
verbose_logger.debug('len(rp_dct): %s\n', len(rp_dct))
487487
for strat in rp_dct.keys():
488488
json_info = self.get_json(fetched_resource, strat)
489489
cpac_prov = json_info['CpacProvenance']
@@ -496,6 +496,7 @@ def get_strats(self, resources, debug=False):
496496
variant_pool[fetched_resource] += val
497497
variant_pool[fetched_resource].append(
498498
f'NO-{val[0]}')
499+
499500
if debug:
500501
verbose_logger.debug('%s sub_pool: %s\n', resource, sub_pool)
501502
total_pool.append(sub_pool)
@@ -1014,6 +1015,7 @@ def gather_pipes(self, wf, cfg, all=False, add_incl=None, add_excl=None):
10141015

10151016
unique_id = out_dct['unique_id']
10161017
resource_idx = resource
1018+
10171019
if isinstance(num_variant, int):
10181020
if True in cfg['functional_preproc',
10191021
'motion_estimates_and_correction',
@@ -1131,7 +1133,7 @@ def gather_pipes(self, wf, cfg, all=False, add_incl=None, add_excl=None):
11311133
nii_name.inputs.keep_ext = True
11321134
wf.connect(id_string, 'out_filename',
11331135
nii_name, 'format_string')
1134-
1136+
11351137
node, out = self.rpool[resource][pipe_idx]['data']
11361138
try:
11371139
wf.connect(node, out, nii_name, 'in_file')
@@ -1439,7 +1441,6 @@ def connect_block(self, wf, cfg, rpool):
14391441
node_name = f'{node_name}_{opt["Name"]}'
14401442

14411443
if debug:
1442-
verbose_logger = getLogger('engine')
14431444
verbose_logger.debug('\n=======================')
14441445
verbose_logger.debug('Node name: %s', node_name)
14451446
prov_dct = \
@@ -1684,7 +1685,9 @@ def ingress_raw_anat_data(wf, rpool, cfg, data_paths, unique_id, part_id,
16841685
rpool.set_data('T2w', anat_flow_T2, 'outputspec.anat', {},
16851686
"", "anat_ingress")
16861687

1687-
if 'freesurfer_dir' in data_paths['anat']:
1688+
ingress_fs = cfg.surface_analysis['freesurfer']['ingress_reconall']
1689+
1690+
if 'freesurfer_dir' in data_paths['anat'] and ingress_fs:
16881691
anat['freesurfer_dir'] = data_paths['anat']['freesurfer_dir']
16891692

16901693
fs_ingress = create_general_datasource('gather_freesurfer_dir')
@@ -1697,27 +1700,27 @@ def ingress_raw_anat_data(wf, rpool, cfg, data_paths, unique_id, part_id,
16971700
{}, "", "freesurfer_config_ingress")
16981701

16991702
recon_outs = {
1700-
'raw-average': 'mri/rawavg.mgz',
1701-
'subcortical-seg': 'mri/aseg.mgz',
1702-
'brainmask': 'mri/brainmask.mgz',
1703-
'wmparc': 'mri/wmparc.mgz',
1704-
'T1': 'mri/T1.mgz',
1705-
'hemi-L_desc-surface_curv': 'surf/lh.curv',
1706-
'hemi-R_desc-surface_curv': 'surf/rh.curv',
1707-
'hemi-L_desc-surfaceMesh_pial': 'surf/lh.pial',
1708-
'hemi-R_desc-surfaceMesh_pial': 'surf/rh.pial',
1709-
'hemi-L_desc-surfaceMesh_smoothwm': 'surf/lh.smoothwm',
1710-
'hemi-R_desc-surfaceMesh_smoothwm': 'surf/rh.smoothwm',
1711-
'hemi-L_desc-surfaceMesh_sphere': 'surf/lh.sphere',
1712-
'hemi-R_desc-surfaceMesh_sphere': 'surf/rh.sphere',
1713-
'hemi-L_desc-surfaceMap_sulc': 'surf/lh.sulc',
1714-
'hemi-R_desc-surfaceMap_sulc': 'surf/rh.sulc',
1715-
'hemi-L_desc-surfaceMap_thickness': 'surf/lh.thickness',
1716-
'hemi-R_desc-surfaceMap_thickness': 'surf/rh.thickness',
1717-
'hemi-L_desc-surfaceMap_volume': 'surf/lh.volume',
1718-
'hemi-R_desc-surfaceMap_volume': 'surf/rh.volume',
1719-
'hemi-L_desc-surfaceMesh_white': 'surf/lh.white',
1720-
'hemi-R_desc-surfaceMesh_white': 'surf/rh.white',
1703+
'pipeline-fs_raw-average': 'mri/rawavg.mgz',
1704+
'pipeline-fs_subcortical-seg': 'mri/aseg.mgz',
1705+
'pipeline-fs_brainmask': 'mri/brainmask.mgz',
1706+
'pipeline-fs_wmparc': 'mri/wmparc.mgz',
1707+
'pipeline-fs_T1': 'mri/T1.mgz',
1708+
'pipeline-fs_hemi-L_desc-surface_curv': 'surf/lh.curv',
1709+
'pipeline-fs_hemi-R_desc-surface_curv': 'surf/rh.curv',
1710+
'pipeline-fs_hemi-L_desc-surfaceMesh_pial': 'surf/lh.pial',
1711+
'pipeline-fs_hemi-R_desc-surfaceMesh_pial': 'surf/rh.pial',
1712+
'pipeline-fs_hemi-L_desc-surfaceMesh_smoothwm': 'surf/lh.smoothwm',
1713+
'pipeline-fs_hemi-R_desc-surfaceMesh_smoothwm': 'surf/rh.smoothwm',
1714+
'pipeline-fs_hemi-L_desc-surfaceMesh_sphere': 'surf/lh.sphere',
1715+
'pipeline-fs_hemi-R_desc-surfaceMesh_sphere': 'surf/rh.sphere',
1716+
'pipeline-fs_hemi-L_desc-surfaceMap_sulc': 'surf/lh.sulc',
1717+
'pipeline-fs_hemi-R_desc-surfaceMap_sulc': 'surf/rh.sulc',
1718+
'pipeline-fs_hemi-L_desc-surfaceMap_thickness': 'surf/lh.thickness',
1719+
'pipeline-fs_hemi-R_desc-surfaceMap_thickness': 'surf/rh.thickness',
1720+
'pipeline-fs_hemi-L_desc-surfaceMap_volume': 'surf/lh.volume',
1721+
'pipeline-fs_hemi-R_desc-surfaceMap_volume': 'surf/rh.volume',
1722+
'pipeline-fs_hemi-L_desc-surfaceMesh_white': 'surf/lh.white',
1723+
'pipeline-fs_hemi-R_desc-surfaceMesh_white': 'surf/rh.white',
17211724
}
17221725

17231726
for key, outfile in recon_outs.items():
@@ -1772,7 +1775,6 @@ def ingress_raw_func_data(wf, rpool, cfg, data_paths, unique_id, part_id,
17721775
# pylint: disable=protected-access
17731776
wf._local_func_scans = local_func_scans
17741777
if cfg.pipeline_setup['Debugging']['verbose']:
1775-
verbose_logger = getLogger('engine')
17761778
verbose_logger.debug('local_func_scans: %s', local_func_scans)
17771779
del local_func_scans
17781780

CPAC/pipeline/schema.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def str_to_bool1_1(x): # pylint: disable=invalid-name
7575
'brain_extraction': {
7676
'using': ['3dSkullStrip', 'BET', 'UNet', 'niworkflows-ants',
7777
'FreeSurfer-BET-Tight', 'FreeSurfer-BET-Loose',
78-
'FreeSurfer-ABCD']
78+
'FreeSurfer-ABCD', 'FreeSurfer-Brainmask']
7979
},
8080
'centrality': {
8181
'method_options': ['degree_centrality', 'eigenvector_centrality',
@@ -437,6 +437,7 @@ def sanitize(filename):
437437
'BiasFieldSmoothingSigma': Maybe(int),
438438
},),
439439
),
440+
440441
'acpc_alignment': Required(
441442
# require 'T1w_brain_ACPC_template' and
442443
# 'T2w_brain_ACPC_template' if 'acpc_target' is 'brain'
@@ -712,7 +713,9 @@ def sanitize(filename):
712713
'surface_analysis': {
713714
'freesurfer': {
714715
'run_reconall': bool1_1,
715-
'reconall_args': Maybe(str)
716+
'reconall_args': Maybe(str),
717+
# 'generate_masks': bool1_1,
718+
'ingress_reconall': bool1_1,
716719
},
717720
'post_freesurfer': {
718721
'run': bool1_1,

0 commit comments

Comments
 (0)