-
Notifications
You must be signed in to change notification settings - Fork 297
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ENH: fsLR output space, cifti output in HCP grayordinate space #1887
Changes from 20 commits
51685b6
a898085
355dd09
a1d2c6f
b2d2fe5
81f63c1
2ba1462
38ee520
72d41c1
f6e69cb
a9be360
fc621dd
b4ccfaa
af3e275
5ed2547
1533207
d979b9c
b142bcd
b74c898
11ded98
9df2503
590b8af
be43eea
311fba6
abeeff9
6c7c048
17abbff
e4d7192
7e5cd86
815bf36
88f7f52
5645707
35dec43
1a8b112
4cc78a8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -748,14 +748,6 @@ def parse_spaces(opts): | |
missing = missing - set(output_spaces.keys()) | ||
output_spaces.update({tpl: {} for tpl in missing}) | ||
|
||
FS_SPACES = set(['fsnative', 'fsaverage', 'fsaverage6', 'fsaverage5']) | ||
if opts.run_reconall and not list(FS_SPACES.intersection(output_spaces.keys())): | ||
print("""\ | ||
Although ``--fs-no-reconall`` was not set (i.e., FreeSurfer is to be run), no FreeSurfer \ | ||
output space (valid values are: %s) was selected. Adding default "fsaverage5" to the \ | ||
list of output spaces.""" % ', '.join(FS_SPACES), file=stderr) | ||
output_spaces['fsaverage5'] = {} | ||
|
||
# Validity of some inputs | ||
# ERROR check if use_aroma was specified, but the correct template was not | ||
if opts.use_aroma and 'MNI152NLin6Asym' not in output_spaces: | ||
|
@@ -765,17 +757,31 @@ def parse_spaces(opts): | |
The argument "MNI152NLin6Asym:res-2" has been automatically added to the list of output spaces \ | ||
(option ``--output-spaces``).""", file=stderr) | ||
|
||
if opts.cifti_output and 'MNI152NLin2009cAsym' not in output_spaces: | ||
if 'MNI152NLin2009cAsym' not in output_spaces: | ||
output_spaces['MNI152NLin2009cAsym'] = {'res': 2} | ||
print("""Option ``--cifti-output`` requires functional images to be resampled to \ | ||
if opts.cifti_output: | ||
# default to HCP grayordinates | ||
FS_CIFTI = set(('fsaverage5', 'fsaverage6')) | ||
if 'fsLR' not in output_spaces and not FS_CIFTI.intersection(output_spaces.keys()): | ||
oesteban marked this conversation as resolved.
Show resolved
Hide resolved
|
||
output_spaces['fsLR'] = {'den': '32k'} | ||
print("""\ | ||
By default, option ``--cifti-output`` resamples functional images to \ | ||
``fsLR`` space. This space has been automatically added to the list of output \ | ||
spaces (option ``--output-spaces``).""", file=stderr) | ||
if 'fsLR' in output_spaces: | ||
den = output_spaces.get('fsLR', {}).get('den') or '32k' | ||
output_spaces['fsLR'] = {'den': den} | ||
if 'MNI152NLin6Asym' not in output_spaces: | ||
output_spaces['MNI152NLin6Asym'] = {'res': '2'} | ||
print("""\ | ||
Option ``--cifti-output`` requires functional images to be resampled to \ | ||
``MNI152NLin6Asym`` space. This space has been automatically added to the list of output \ | ||
spaces (option ``--output-spaces``).""", file=stderr) | ||
|
||
else: | ||
if 'MNI152NLin2009cAsym' not in output_spaces: | ||
output_spaces['MNI152NLin2009cAsym'] = {'res': 2} | ||
print("""Option ``--cifti-output`` requires functional images to be resampled to \ | ||
``MNI152NLin2009cAsym`` space. Such template identifier has been automatically added to the \ | ||
list of output spaces (option "--output-space").""", file=stderr) | ||
if not [s for s in output_spaces if s in ('fsaverage5', 'fsaverage6')]: | ||
output_spaces['fsaverage5'] = {} | ||
print("""Option ``--cifti-output`` requires functional images to be resampled to \ | ||
``fsaverage`` space. The argument ``fsaverage:den-10k`` (a.k.a ``fsaverage5``) has been \ | ||
automatically added to the list of output spaces (option ``--output-space``).""", file=stderr) | ||
list of output spaces (option "--output-spaces").""", file=stderr) | ||
|
||
if opts.template_resampling_grid is not None: | ||
print("""Option ``--template-resampling-grid`` is deprecated, please specify \ | ||
|
@@ -786,6 +792,17 @@ def parse_spaces(opts): | |
if key in get_templates(): | ||
output_spaces[key]['res'] = opts.template_resampling_grid[0] | ||
|
||
if 'fsLR' in output_spaces and 'fsaverage' not in output_spaces: | ||
# resample to fsLR from highest density fsaverage | ||
output_spaces['fsaverage'] = {'den': '164k'} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly, now asking for CIFTIs in fsLR means that I'm also getting GIFTI outputs in fsaverage space. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yep, see above |
||
|
||
FS_SPACES = set(('fsnative', 'fsaverage', 'fsaverage6', 'fsaverage5')) | ||
if opts.run_reconall and not FS_SPACES.intersection(output_spaces.keys()): | ||
print("""\ | ||
Although ``--fs-no-reconall`` was not set (i.e., FreeSurfer is to be run), no FreeSurfer \ | ||
output space (valid values are: %s) was selected. Adding default "fsaverage5" to the \ | ||
list of output spaces.""" % ', '.join(FS_SPACES), file=stderr) | ||
output_spaces['fsaverage5'] = {} | ||
return output_spaces | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -412,7 +412,7 @@ def init_func_preproc_wf( | |
outputnode = pe.Node(niu.IdentityInterface( | ||
fields=['bold_t1', 'bold_t1_ref', 'bold_mask_t1', 'bold_aseg_t1', 'bold_aparc_t1', | ||
'bold_std', 'bold_std_ref', 'bold_mask_std', 'bold_aseg_std', 'bold_aparc_std', | ||
'bold_native', 'bold_cifti', 'cifti_variant', 'cifti_variant_key', 'surfaces', | ||
'bold_native', 'bold_cifti', 'cifti_variant', 'cifti_metadata', 'surfaces', | ||
'confounds', 'aroma_noise_ics', 'melodic_mix', 'nonaggr_denoised_file', | ||
'confounds_metadata']), | ||
name='outputnode') | ||
|
@@ -431,10 +431,11 @@ def init_func_preproc_wf( | |
name='summary', mem_gb=DEFAULT_MEMORY_MIN_GB, run_without_submitting=True) | ||
summary.inputs.dummy_scans = dummy_scans | ||
|
||
# CIfTI output: currently, we only support fsaverage{5,6} | ||
cifti_spaces = set(s for s in output_spaces.keys() if s in ('fsaverage5', 'fsaverage6')) | ||
# CIFTI output | ||
cifti_spaces = {'fsLR'} if 'fsLR' in output_spaces else \ | ||
set(output_spaces.keys()).intersection(('fsaverage5', 'fsaverage6')) | ||
fsaverage_den = output_spaces.get('fsaverage', {}).get('den') | ||
if fsaverage_den: | ||
if fsaverage_den and 'fsLR' not in cifti_spaces: | ||
cifti_spaces.add(FSAVERAGE_DENSITY[fsaverage_den]) | ||
cifti_output = cifti_output and cifti_spaces | ||
func_derivatives_wf = init_func_derivatives_wf( | ||
|
@@ -463,7 +464,7 @@ def init_func_preproc_wf( | |
('nonaggr_denoised_file', 'inputnode.nonaggr_denoised_file'), | ||
('bold_cifti', 'inputnode.bold_cifti'), | ||
('cifti_variant', 'inputnode.cifti_variant'), | ||
('cifti_variant_key', 'inputnode.cifti_variant_key'), | ||
('cifti_metadata', 'inputnode.cifti_metadata'), | ||
('confounds_metadata', 'inputnode.confounds_metadata'), | ||
]), | ||
]) | ||
|
@@ -923,10 +924,12 @@ def init_func_preproc_wf( | |
# SURFACES ################################################################################## | ||
surface_spaces = [space for space in output_spaces.keys() if space.startswith('fs')] | ||
if freesurfer and surface_spaces: | ||
fslr_density = output_spaces.get('fsLR', {}).get('den', '32k') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We'll need to address #1895 if we want this to work. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i've opened nipreps/smriprep#145 - since that isn't exclusive to this I'll submit a fix separate from this. A quick workaround is to specify at least one parameter for |
||
LOGGER.log(25, 'Creating BOLD surface-sampling workflow.') | ||
bold_surf_wf = init_bold_surf_wf(mem_gb=mem_gb['resampled'], | ||
output_spaces=surface_spaces, | ||
medial_surface_nan=medial_surface_nan, | ||
fslr_density=fslr_density, | ||
name='bold_surf_wf') | ||
workflow.connect([ | ||
(inputnode, bold_surf_wf, [ | ||
|
@@ -944,26 +947,35 @@ def init_func_preproc_wf( | |
*Grayordinates* files [@hcppipelines], which combine surface-sampled | ||
data and volume-sampled data, were also generated. | ||
""" | ||
cifti_volume = "MNI152NLin6Asym" if 'fsLR' in cifti_spaces else "MNI152NLin2009cAsym" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought they used an FSL-packaged (and slightly weird) version of the template. Do we need to account for that? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we are using the same labelled MNI template the HCP folks use to generate the CIFTIs, which should be in same space as the template - what do you mean by slightly weird? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I might be misremembering. During the TemplateFlow changeover we switched from using FSL's packaged template (MNI152NLin2009cAsym) to MNI's, and there were some differences. I thought using FSL's distribution was something we'd copied from HCP. @oesteban will probably know better. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The "MNI" distributed with FSL is an unofficial version created by A. Janke with the same data and methodology of the official Then, the HCP folks resampled the 1mm^3 grid to different resolutions that seem useful to them. We originally placed these files under the During the TemplateFlow changeover, we did not switch from the official, latest MNI template ( Hopefully, this clarifies the spotty connections between TemplateFlow, the "MNI" template(s) and this PR. |
||
select_std = pe.Node(KeySelect(fields=['bold_std']), | ||
name='select_std', run_without_submitting=True) | ||
select_std.inputs.key = 'MNI152NLin2009cAsym' | ||
select_std.inputs.key = cifti_volume | ||
|
||
gen_cifti = pe.MapNode(GenerateCifti(), iterfield=["surface_target", "gifti_files"], | ||
order_surfs = pe.Node(niu.Function(function=_order_surfs, | ||
output_names=["surface_files"]), | ||
name='order_surfs', run_without_submitting=True) | ||
order_surfs.inputs.targets = list(cifti_spaces) | ||
|
||
gen_cifti = pe.MapNode(GenerateCifti(), iterfield=["surface_target", "surface_bolds"], | ||
name="gen_cifti") | ||
gen_cifti.inputs.TR = metadata.get("RepetitionTime") | ||
gen_cifti.inputs.surface_target = list(cifti_spaces) | ||
gen_cifti.inputs.density = fslr_density | ||
|
||
workflow.connect([ | ||
(bold_std_trans_wf, select_std, [ | ||
('outputnode.templates', 'keys'), | ||
('outputnode.bold_std', 'bold_std')]), | ||
(bold_surf_wf, gen_cifti, [ | ||
('outputnode.surfaces', 'gifti_files')]), | ||
(bold_surf_wf, order_surfs, [('outputnode.surfaces', 'in_surfs')]), | ||
(order_surfs, gen_cifti, [('surface_files', 'surface_bolds')]), | ||
(inputnode, gen_cifti, [('subjects_dir', 'subjects_dir')]), | ||
(select_std, gen_cifti, [('bold_std', 'bold_file')]), | ||
(select_std, gen_cifti, [ | ||
('bold_std', 'bold_file'), | ||
('key', 'volume_target')]), | ||
(gen_cifti, outputnode, [('out_file', 'bold_cifti'), | ||
('variant', 'cifti_variant'), | ||
('variant_key', 'cifti_variant_key')]), | ||
('out_metadata', 'cifti_metadata')]), | ||
]) | ||
|
||
# REPORTING ############################################################ | ||
|
@@ -1042,6 +1054,15 @@ def _to_join(in_file, join_file): | |
from niworkflows.interfaces.utils import JoinTSVColumns | ||
if join_file is None: | ||
return in_file | ||
|
||
res = JoinTSVColumns(in_file=in_file, join_file=join_file).run() | ||
return res.outputs.out_file | ||
|
||
|
||
def _order_surfs(targets, in_surfs): | ||
"""Reorder list of surface_files into [L,R] sub-lists""" | ||
surface_files = [] | ||
targets = targets if 'fsLR' not in targets else ('fsLR',) | ||
for target in targets: | ||
target_files = [f for f in in_surfs if f.endswith("{}.gii".format(target))] | ||
surface_files.append(target_files) | ||
return surface_files |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't this be
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Related question: how much time would add to run this with
--output-spaces fsLR <...> --cifti-outputs
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does
space-fsaverage
imply subcortical structures inMNI152NLin2009cAsym
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure exactly how long, the biggest addon would be resampling to fsaverage:164k (resampling to fsLR is fairly quick). Would also spike the size of outputs, as BOLD in fsaverage is fairly big.
If this sounds reasonable, I can add it in