Skip to content

Commit edd433f

Browse files
committed
Merge branch 'develop' into upgrade/python
2 parents 668ab59 + ee47013 commit edd433f

39 files changed

+562
-347
lines changed

.github/READTHIS.md

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<!-- Don't rename to '.github/README.md' or it will override the root readme. -->
2+
3+
# C-PAC/.github README
4+
5+
This directory contains Dockerfiles, scripts, requirements files, and workflow configurations for [this repository's GitHub Actions](https://github.com/FCP-INDI/C-PAC/actions).
6+
7+
When updating these files, please update this README as necessary.
8+
9+
[The `workflows` directory](./workflows) contains the configurations for the Actions themselves. The other directories support these configs.
10+
11+
```mermaid
12+
flowchart TD
13+
subgraph Dockerfiles
14+
base[base-.*]
15+
16+
cpacdockerfiles["C-PAC.develop-(?!lite).*"]
17+
18+
cpaclitedockerfile[C-PAC.develop-lite.*]
19+
20+
stagedockerfiles[AFNI.*\nANTs.*\nc3d.*\nconnectome-workbench.*\nFSL.*\nICA-AROMA.*\nmsm.*]
21+
22+
ubuntudockerfiles[Ubuntu.*]
23+
end
24+
subgraph scripts
25+
get_package_id.py
26+
get_pr_base_shas
27+
local_ghcr
28+
end
29+
subgraph smoke_test_participant.yml
30+
smoke_test_human
31+
smoke_test_nhp
32+
smoke_test_rodent
33+
end
34+
subgraph stage_requirements
35+
.*.txt
36+
end
37+
subgraph workflows
38+
subgraph build_stages.yml
39+
40+
ubuntu[[Ubnutu]]-->stages[[stages]]-->build-base[[build-base]]
41+
42+
end
43+
subgraph build_C-PAC.yml
44+
bCPAC[[C-PAC]]
45+
end
46+
subgraph build_and_test.yml
47+
Circle_tests[[Circle_tests]]
48+
49+
C-PAC[[C-PAC]]-->bCPAC
50+
C-PAC-->Circle_tests
51+
C-PAC-->smoke-tests-participant
52+
C-PAC-->C-PAC-lite
53+
54+
C-PAC-lite[[C-PAC-lite]]-->bCPAC
55+
C-PAC-lite-->Circle_tests
56+
C-PAC-lite-->smoke-tests-participant
57+
58+
C-PAC-ABCD-HCP[[C-PAC-ABCD-HCP]]-->bCPAC
59+
C-PAC-ABCD-HCP-->Circle_tests
60+
C-PAC-ABCD-HCP-->smoke-tests-participant
61+
62+
C-PAC-fMRIPrep[[C-PAC-fMRIPrep-LTS]]-->bCPAC
63+
C-PAC-fMRIPrep-->Circle_tests
64+
C-PAC-fMRIPrep-->smoke-tests-participant
65+
66+
smoke-tests-participant[[smoke-tests-participant]]
67+
end
68+
69+
check_updated_preconfigs.yml-->build_stages.yml
70+
71+
delete_images.yml
72+
end
73+
74+
subgraph yaml_template[CPAC/utils/configuration/yaml_template.py]
75+
76+
update_all_preconfigs[[update_all_preconfigs]]
77+
end
78+
79+
base<-->build-base
80+
81+
Circle_tests-->CircleCI((Run tests on Circle CI))
82+
83+
build_stages.yml-->build_and_test.yml
84+
85+
check_updated_preconfigs.yml<-->get_pr_base_shas
86+
check_updated_preconfigs.yml-->update_all_preconfigs
87+
88+
cpacdockerfiles<-->C-PAC
89+
cpacdockerfiles<-->C-PAC-ABCD-HCP
90+
cpacdockerfiles<-->C-PAC-fMRIPrep
91+
92+
cpaclitedockerfile<-->C-PAC-lite
93+
94+
delete>delete branch]-->delete_images.yml
95+
96+
delete_images.yml<-->get_package_id.py
97+
98+
build-base<-->local_ghcr
99+
bCPAC<-->local_ghcr
100+
stages<-->local_ghcr
101+
102+
push>git push]-->check_updated_preconfigs.yml
103+
104+
smoke-tests-participant-->smoke_test_human
105+
smoke-tests-participant-->smoke_test_nhp
106+
smoke-tests-participant-->smoke_test_rodent
107+
108+
stagedockerfiles<-->stages
109+
110+
build-base<-->.*.txt
111+
112+
ubuntudockerfiles<-->ubuntu
113+
```
114+
115+
In this [Mermaid flowchart](https://mermaid.js.org/syntax/flowchart.html), these shapes are used:
116+
117+
concept | shape
118+
---|---
119+
directory | `subgraph`
120+
file | rectangle (`[]`) or `subgraph`
121+
workflow job | subprocess (`[[]]`)
122+
trigger action | asymetric (`>]`)
123+
external API | circle (`(())`)

.github/workflows/deploy_to_Docker_Hub.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ jobs:
3232
TAG1=release-${{ github.ref_name }}$VARIANT
3333
DOCKER_TAG=$(echo "ghcr.io/${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
3434
echo "original tag: ${DOCKER_TAG}:${TAG1}"
35+
docker pull ${DOCKER_TAG}:${TAG1}
3536
docker tag ${DOCKER_TAG}:${TAG1} fcpindi/c-pac:${TAG1}
3637
docker push fcpindi/c-pac:${TAG1}
3738
if [[ ${{ github.ref_name }} =~ ${TAG_PATTERN} ]]

.github/workflows/smoke_test_participant.yml

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -122,14 +122,6 @@ jobs:
122122
- ''
123123
participant:
124124
- 032102 032106 032164 032167 032130 032128 2215 2312 032191 032195
125-
include:
126-
# requires T2w
127-
- preconfig: monkey-ABCD
128-
variant: ''
129-
participant: 032102 032106 032130 032128 032191 032195
130-
- preconfig: monkey-ABCD
131-
variant: ABCD-HCP
132-
participant: 032102 032106 032130 032128 032191 032195
133125
steps:
134126
- name: Get C-PAC
135127
run: |

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8888
- Added NodeBlock information to `pypeline.log` when verbose debugging is on
8989
- Added the ability to ingress FreeSurfer data into CPAC
9090
- Added the ability to toggle FreeSurfer derived masks for brain extraction
91+
- Added an optional volume center to FD-J calculation
92+
- Added new preconfig `abcd-prep`, which performs minimal preprocessing on the T1w data in preparation for Freesurfer Recon-All
9193

9294
### Changed
9395

CPAC/anat_preproc/anat_preproc.py

Lines changed: 61 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
mri_convert, \
1717
wb_command, \
1818
fslmaths_command, \
19-
VolumeRemoveIslands
19+
VolumeRemoveIslands, \
20+
normalize_wmparc
2021
from CPAC.pipeline.engine import flatten_list
2122
from CPAC.utils.docs import docstring_parameter
2223
from CPAC.utils.interfaces.fsl import Merge as fslMerge
@@ -914,16 +915,44 @@ def freesurfer_abcd_brain_connector(wf, cfg, strat_pool, pipe_num, opt):
914915
### ABCD harmonization - anatomical brain mask generation ###
915916
# Ref: https://github.com/DCAN-Labs/DCAN-HCP/blob/master/PostFreeSurfer/PostFreeSurferPipeline.sh#L151-L156
916917

918+
917919
wmparc_to_nifti = pe.Node(util.Function(input_names=['in_file',
918920
'reslice_like',
919921
'args'],
920922
output_names=['out_file'],
921923
function=mri_convert),
922924
name=f'wmparc_to_nifti_{pipe_num}')
923-
wmparc_to_nifti.inputs.args = '-rt nearest'
925+
926+
# Register wmparc file if ingressing FreeSurfer data
927+
if strat_pool.check_rpool('pipeline-fs_xfm'):
928+
929+
wmparc_to_native = pe.Node(util.Function(input_names=['source_file',
930+
'target_file',
931+
'xfm',
932+
'out_file'],
933+
output_names=['transformed_file'],
934+
function=normalize_wmparc),
935+
name=f'wmparc_to_native_{pipe_num}')
936+
937+
wmparc_to_native.inputs.out_file = 'wmparc_warped.mgz'
938+
939+
node, out = strat_pool.get_data('pipeline-fs_wmparc')
940+
wf.connect(node, out, wmparc_to_native, 'source_file')
941+
942+
node, out = strat_pool.get_data('pipeline-fs_raw-average')
943+
wf.connect(node, out, wmparc_to_native, 'target_file')
924944

925-
node, out = strat_pool.get_data('pipeline-fs_wmparc')
926-
wf.connect(node, out, wmparc_to_nifti, 'in_file')
945+
node, out = strat_pool.get_data('pipeline-fs_xfm')
946+
wf.connect(node, out, wmparc_to_native, 'xfm')
947+
948+
wf.connect(wmparc_to_native, 'transformed_file', wmparc_to_nifti, 'in_file')
949+
950+
else:
951+
952+
node, out = strat_pool.get_data('pipeline-fs_wmparc')
953+
wf.connect(node, out, wmparc_to_nifti, 'in_file')
954+
955+
wmparc_to_nifti.inputs.args = '-rt nearest'
927956

928957
node, out = strat_pool.get_data('desc-preproc_T1w')
929958
wf.connect(node, out, wmparc_to_nifti, 'reslice_like')
@@ -1244,21 +1273,24 @@ def acpc_align_head(wf, cfg, strat_pool, pipe_num, opt=None):
12441273
["anatomical_preproc", "run"]],
12451274
"option_key": "None",
12461275
"option_val": "None",
1247-
"inputs": ["desc-head_T1w",
1248-
"desc-preproc_T1w",
1276+
"inputs": ["desc-preproc_T1w",
1277+
"desc-head_T1w",
12491278
"T1w-ACPC-template"],
12501279
"outputs": ["desc-head_T1w",
12511280
"desc-preproc_T1w",
12521281
"from-T1w_to-ACPC_mode-image_desc-aff2rig_xfm"]}
12531282
'''
1254-
1283+
1284+
# NOTE: desc-preproc_T1w and desc-head_T1w are both needed in this
1285+
# nodeblock despite the list called in get_data() below
1286+
12551287
acpc_align = acpc_alignment(config=cfg,
12561288
acpc_target=cfg.anatomical_preproc[
12571289
'acpc_alignment']['acpc_target'],
12581290
mask=False,
12591291
wf_name=f'acpc_align_{pipe_num}')
12601292

1261-
node, out = strat_pool.get_data(['desc-head_T1w', 'desc-preproc_T1w'])
1293+
node, out = strat_pool.get_data(['desc-preproc_T1w','desc-head_T1w'])
12621294
wf.connect(node, out, acpc_align, 'inputspec.anat_leaf')
12631295

12641296
node, out = strat_pool.get_data('T1w-ACPC-template')
@@ -1772,6 +1804,8 @@ def brain_mask_freesurfer_abcd(wf, cfg, strat_pool, pipe_num, opt=None):
17721804
"option_val": "FreeSurfer-ABCD",
17731805
"inputs": ["desc-preproc_T1w",
17741806
"pipeline-fs_wmparc",
1807+
"pipeline-fs_raw-average",
1808+
"pipeline-fs_xfm",
17751809
"freesurfer-subject-dir"],
17761810
"outputs": ["space-T1w_desc-brain_mask"]}
17771811
'''
@@ -1813,6 +1847,8 @@ def brain_mask_acpc_freesurfer_abcd(wf, cfg, strat_pool, pipe_num, opt=None):
18131847
"option_val": "FreeSurfer-ABCD",
18141848
"inputs": ["desc-preproc_T1w",
18151849
"pipeline-fs_wmparc",
1850+
"pipeline-fs_raw-average",
1851+
"pipeline-fs_xfm",
18161852
"freesurfer-subject-dir"],
18171853
"outputs": ["space-T1w_desc-acpcbrain_mask"]}
18181854
'''
@@ -2533,10 +2569,10 @@ def brain_extraction_temp_T2(wf, cfg, strat_pool, pipe_num, opt=None):
25332569
def freesurfer_abcd_preproc(wf, cfg, strat_pool, pipe_num, opt=None):
25342570
'''
25352571
{"name": "freesurfer_abcd_preproc",
2536-
"config": ["anatomical_preproc", "brain_extraction"],
2537-
"switch": "None",
2538-
"option_key": "using",
2539-
"option_val": "FreeSurfer-ABCD",
2572+
"config": ["surface_analysis", "abcd_prefreesurfer_prep"],
2573+
"switch": ["run"],
2574+
"option_key": "None",
2575+
"option_val": "None",
25402576
"inputs": ["desc-preproc_T1w",
25412577
"T1w-template",
25422578
"T1w-brain-template-mask",
@@ -2545,16 +2581,17 @@ def freesurfer_abcd_preproc(wf, cfg, strat_pool, pipe_num, opt=None):
25452581
"freesurfer-subject-dir"],
25462582
"outputs": ["desc-restore_T1w",
25472583
"desc-restore-brain_T1w",
2584+
"desc-ABCDpreproc_T1w",
25482585
"pipeline-fs_desc-fast_biasfield",
25492586
"pipeline-fs_hemi-L_desc-surface_curv",
2550-
"pipeline-fs_hemi-R_desc-surface_curv",
2587+
"pipeline-fs_hemi-R_desc-surface_curv",
25512588
"pipeline-fs_hemi-L_desc-surfaceMesh_pial",
25522589
"pipeline-fs_hemi-R_desc-surfaceMesh_pial",
25532590
"pipeline-fs_hemi-L_desc-surfaceMesh_smoothwm",
25542591
"pipeline-fs_hemi-R_desc-surfaceMesh_smoothwm",
25552592
"pipeline-fs_hemi-L_desc-surfaceMesh_sphere",
25562593
"pipeline-fs_hemi-R_desc-surfaceMesh_sphere",
2557-
"pipeline-fs_hemi-L_desc-surfaceMap_sulc",
2594+
"pipeline-fs_hemi-L_desc-surfaceMap_sulc",
25582595
"pipeline-fs_hemi-R_desc-surfaceMap_sulc",
25592596
"pipeline-fs_hemi-L_desc-surfaceMap_thickness",
25602597
"pipeline-fs_hemi-R_desc-surfaceMap_thickness",
@@ -2565,7 +2602,6 @@ def freesurfer_abcd_preproc(wf, cfg, strat_pool, pipe_num, opt=None):
25652602
"pipeline-fs_wmparc",
25662603
"freesurfer-subject-dir"]}
25672604
'''
2568-
25692605
# fnirt-based brain extraction
25702606
brain_extraction = fnirt_based_brain_extraction(config=cfg,
25712607
wf_name=f'fnirt_based_brain_extraction_{pipe_num}')
@@ -2657,52 +2693,15 @@ def freesurfer_abcd_preproc(wf, cfg, strat_pool, pipe_num, opt=None):
26572693
wf.connect(average_brain, 'out_stat',
26582694
normalize_head, 'number')
26592695

2660-
if strat_pool.check_rpool('freesurfer-subject-dir'):
2661-
outputs = {
2696+
outputs = {
26622697
'desc-restore_T1w': (fast_correction, 'outputspec.anat_restore'),
26632698
'desc-restore-brain_T1w': (fast_correction,
26642699
'outputspec.anat_brain_restore'),
2665-
'pipeline-fs_desc-fast_biasfield': (fast_correction, 'outputspec.bias_field')}
2666-
return (wf, outputs)
2667-
2668-
else:
2669-
### recon-all -all step ###
2670-
reconall = pe.Node(interface=freesurfer.ReconAll(),
2671-
name=f'anat_freesurfer_{pipe_num}',
2672-
mem_gb=2.7)
2673-
2674-
sub_dir = cfg.pipeline_setup['working_directory']['path']
2675-
freesurfer_subject_dir = os.path.join(sub_dir,
2676-
'cpac_'+cfg['subject_id'],
2677-
f'anat_preproc_freesurfer_{pipe_num}',
2678-
'anat_freesurfer')
2679-
2680-
# create the directory for FreeSurfer node
2681-
if not os.path.exists(freesurfer_subject_dir):
2682-
os.makedirs(freesurfer_subject_dir)
2683-
2684-
reconall.inputs.directive = 'all'
2685-
reconall.inputs.subjects_dir = freesurfer_subject_dir
2686-
reconall.inputs.openmp = cfg.pipeline_setup['system_config']['num_OMP_threads']
2687-
2688-
wf.connect(normalize_head, 'out_file',
2689-
reconall, 'T1_files')
2690-
2691-
wf, hemisphere_outputs = freesurfer_hemispheres(wf, reconall, pipe_num)
2692-
2693-
outputs = {
2694-
'desc-restore_T1w': (fast_correction, 'outputspec.anat_restore'),
2695-
'desc-restore-brain_T1w': (fast_correction,
2696-
'outputspec.anat_brain_restore'),
2697-
'pipeline-fs_desc-fast_biasfield': (fast_correction, 'outputspec.bias_field'),
2698-
'pipeline-fs_wmparc': (reconall, 'wmparc'),
2699-
'freesurfer-subject-dir': (reconall, 'subjects_dir'),
2700-
**hemisphere_outputs
2701-
}
2702-
2700+
'pipeline-fs_desc-fast_biasfield': (fast_correction, 'outputspec.bias_field'),
2701+
'desc-ABCDpreproc_T1w': (normalize_head, 'out_file')
2702+
}
27032703
return (wf, outputs)
27042704

2705-
27062705
# we're grabbing the postproc outputs and appending them to
27072706
# the reconall outputs
27082707
@docstring_parameter(postproc_outputs=str(flatten_list(freesurfer_abcd_preproc, 'outputs')
@@ -2715,7 +2714,8 @@ def freesurfer_reconall(wf, cfg, strat_pool, pipe_num, opt=None):
27152714
"switch": ["run_reconall"],
27162715
"option_key": "None",
27172716
"option_val": "None",
2718-
"inputs": ["desc-preproc_T1w"],
2717+
"inputs": [["desc-ABCDpreproc_T1w",
2718+
"desc-preproc_T1w"]],
27192719
"outputs": ["freesurfer-subject-dir",
27202720
"pipeline-fs_raw-average",
27212721
"pipeline-fs_subcortical-seg",
@@ -2748,7 +2748,7 @@ def freesurfer_reconall(wf, cfg, strat_pool, pipe_num, opt=None):
27482748
reconall.inputs.args = cfg.surface_analysis['freesurfer'][
27492749
'reconall_args']
27502750

2751-
node, out = strat_pool.get_data("desc-preproc_T1w")
2751+
node, out = strat_pool.get_data(["desc-ABCDpreproc_T1w","desc-preproc_T1w"])
27522752
wf.connect(node, out, reconall, 'T1_files')
27532753

27542754
wf, hemisphere_outputs = freesurfer_hemispheres(wf, reconall, pipe_num)
@@ -2983,9 +2983,9 @@ def fast_bias_field_correction(config=None, wf_name='fast_bias_field_correction'
29832983
def correct_restore_brain_intensity_abcd(wf, cfg, strat_pool, pipe_num, opt=None):
29842984
'''
29852985
{"name": "correct_restore_brain_intensity_abcd",
2986-
"config": ["anatomical_preproc", "brain_extraction"],
2987-
"switch": "None",
2988-
"option_key": "using",
2986+
"config": "None",
2987+
"switch": ["anatomical_preproc", "brain_extraction", "run"],
2988+
"option_key": ["anatomical_preproc", "brain_extraction", "using"],
29892989
"option_val": "FreeSurfer-ABCD",
29902990
"inputs": [("desc-preproc_T1w",
29912991
"desc-n4_T1w",

0 commit comments

Comments
 (0)