From a8eefd5432bd7c0f29672545eb2d187fce7ef55a Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Wed, 4 Dec 2024 15:37:37 -0500 Subject: [PATCH 1/3] Keep working. --- .zenodo.json | 5 - REFERENCES.md | 15 --- src/smripost_linc/__main__.py | 9 -- src/smripost_linc/_version.pyi | 4 - src/smripost_linc/workflows/base.py | 2 + src/smripost_linc/workflows/freesurfer.py | 115 +++++++++++++++++++++- 6 files changed, 115 insertions(+), 35 deletions(-) delete mode 100644 REFERENCES.md delete mode 100644 src/smripost_linc/__main__.py delete mode 100644 src/smripost_linc/_version.pyi diff --git a/.zenodo.json b/.zenodo.json index c403eea..3ed634a 100644 --- a/.zenodo.json +++ b/.zenodo.json @@ -33,11 +33,6 @@ "identifier": "https://smripost_linc.org", "relation": "documents", "scheme": "url" - }, - { - "identifier": "10.1038/s41592-018-0235-4", - "relation": "isPartOf", - "scheme": "doi" } ], "upload_type": "software" diff --git a/REFERENCES.md b/REFERENCES.md deleted file mode 100644 index 0cceb35..0000000 --- a/REFERENCES.md +++ /dev/null @@ -1,15 +0,0 @@ -| Tool (**Package**) | Citation(s) | Link to code or documentation | -|-----|-----|-----| -| **FSL** | | https://doi.org/10.1016/j.neuroimage.2004.07.051 https://doi.org/10.1016/j.neuroimage.2008.10.055 https://doi.org/10.1016/j.neuroimage.2011.09.015 -| SUSAN | https://doi.org/10.1023/A:1007963824710 | https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/SUSAN | -| MELODIC | | https://fsl.fmrib.ox.ac.uk/fsl/fslwiki/MELODIC | -| ICA-AROMA | http://www.sciencedirect.com/science/article/pii/S1053811915001822 | https://github.com/rhr-pruim/ICA-AROMA/ | -| **Other** | | | -| nibabel | https://doi.org/10.5281/zenodo.60808 | https://github.com/nipy/nibabel/ | -| nilearn | https://doi.org/10.3389/fninf.2014.00014 | https://github.com/nilearn/nilearn/ | -| nipype | https://doi.org/10.3389/fninf.2011.00013 https://doi.org/10.5281/zenodo.581704 | https://github.com/nipy/nipype/ | -| **Graphics** | | | -| seaborn | https://doi.org/10.5281/zenodo.883859 | https://github.com/mwaskom/seaborn | -| matplotlib 2.0.0 | https://doi.org/10.5281/zenodo.248351 | https://github.com/matplotlib/matplotlib | -| cwebp | https://developers.google.com/speed/webp/docs/webp_study https://developers.google.com/speed/webp/docs/webp_lossless_alpha_study | https://developers.google.com/speed/webp/ | -| SVGO | | https://github.com/svg/svgo | diff --git a/src/smripost_linc/__main__.py b/src/smripost_linc/__main__.py deleted file mode 100644 index e5c421c..0000000 --- a/src/smripost_linc/__main__.py +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-FileCopyrightText: 2023-present Chris Markiewicz -# -# SPDX-License-Identifier: Apache-2.0 -import sys - -if __name__ == '__main__': - from .cli import smripost_linc - - sys.exit(smripost_linc()) diff --git a/src/smripost_linc/_version.pyi b/src/smripost_linc/_version.pyi deleted file mode 100644 index f3c1fd3..0000000 --- a/src/smripost_linc/_version.pyi +++ /dev/null @@ -1,4 +0,0 @@ -__version__: str -__version_tuple__: tuple[str, ...] -version: str -version_tuple: tuple[str, ...] diff --git a/src/smripost_linc/workflows/base.py b/src/smripost_linc/workflows/base.py index fb6bcd8..70b58cf 100644 --- a/src/smripost_linc/workflows/base.py +++ b/src/smripost_linc/workflows/base.py @@ -405,6 +405,8 @@ def init_single_run_wf(anat_file, atlases): ]), ]) # fmt:skip + # Calculate myelin map if both T1w and T2w are available + # Fill-in datasinks seen so far for node in workflow.list_node_names(): node_name = node.split('.')[-1] diff --git a/src/smripost_linc/workflows/freesurfer.py b/src/smripost_linc/workflows/freesurfer.py index eb3f3c5..378c654 100644 --- a/src/smripost_linc/workflows/freesurfer.py +++ b/src/smripost_linc/workflows/freesurfer.py @@ -2,6 +2,7 @@ # vi: set ft=python sts=4 ts=4 sw=4 et: """Workflows for working with FreeSurfer derivatives.""" +from nipype.interfaces import freesurfer as fs from nipype.interfaces import utility as niu from nipype.pipeline import engine as pe from niworkflows.engine.workflows import LiterateWorkflow as Workflow @@ -45,8 +46,6 @@ def init_parcellate_external_wf( parcellated_tsvs Parcellated TSV files. One for each atlas and hemisphere. """ - from nipype.interfaces import freesurfer as fs - from smripost_linc.interfaces.bids import DerivativesDataSink from smripost_linc.interfaces.freesurfer import CopyAnnots, FreesurferFiles from smripost_linc.interfaces.misc import ParcellationStats2TSV @@ -236,3 +235,115 @@ def symlink_freesurfer_dir(freesurfer_dir, output_dir=None): ) return str(output_dir) + + +def init_convert_metrics_to_cifti_wf(name='convert_metrics_to_cifti_wf'): + """Convert FreeSurfer metrics from MGH format to CIFTI format in fsLR space.""" + workflow = Workflow(name=name) + + inputnode = pe.Node( + niu.IdentityInterface( + fields=[ + 'subject_id', + 'freesurfer_dir', + ], + ), + name='inputnode', + ) + + # Convert FreeSurfer metrics to CIFTI + collect_fsaverage_surfaces = pe.Node( + CollectFSAverageSurfaces(), + name='collect_fsaverage_surfaces', + ) + workflow.connect([ + (inputnode, collect_fsaverage_surfaces, [('freesurfer_dir', 'freesurfer_dir')]), + ]) # fmt:skip + + convert_gifti_to_cifti = pe.MapNode( + CiftiCreateDenseScalar(), + name='convert_gifti_to_cifti', + iterfield=['lh_gifti', 'rh_gifti'], + ) + + for hemi in ['lh', 'rh']: + convert_to_gifti = pe.MapNode( + fs.MRIsConvert(out_datatype='gii'), + name=f'convert_to_gifti_{hemi}', + iterfield=['in_file'], + ) + workflow.connect([ + (collect_fsaverage_surfaces, convert_to_gifti, [('out_files', 'in_file')]), + (convert_to_gifti, convert_to_cifti, [('out_file', f'{hemi}_gifti')]), + ]) # fmt:skip + + warp_fsaverage_to_fslr = pe.MapNode( + niu.Function( + input_names=['in_file', 'hemi'], + output_names=['out_file'], + function=convert_gifti_to_cifti, + ), + name='warp_fsaverage_to_fslr', + iterfield=['in_file'], + ) + warp_fsaverage_to_fslr.inputs.hemi = hemi + workflow.connect([ + (convert_to_gifti, warp_fsaverage_to_fslr, [('out_file', 'in_file')]), + (warp_fsaverage_to_fslr, convert_gifti_to_cifti, [('out_file', f'{hemi}_gifti')]), + ]) # fmt:skip + + ds_cifti = pe.MapNode( + DerivativesDataSink( + source_file=name_source, + space='fsLR', + extension='.dscalar.nii', + ), + name='ds_cifti', + iterfield=['in_file', 'suffix'], + ) + workflow.connect([ + (collect_fsaverage_surfaces, ds_cifti, [('names', 'in_file')]), + (convert_gifti_to_cifti, ds_cifti, [('out_file', 'in_file')]), + ]) # fmt:skip + + return workflow + + +def convert_gifti_to_cifti(lh_gifti, rh_gifti): + """Convert fsaverage-space GIFTI files to a CIFTI file in fsLR space.""" + import os + import subprocess + from pathlib import Path + + from neuromaps.transforms import fsaverage_to_fslr + + out_file = os.path.abspath('cifti.dscalar.nii') + + l_fslr = fsaverage_to_fslr( + lh_gifti, + target_density='164k', + hemi='L', + method='linear', + ) + r_fslr = fsaverage_to_fslr( + rh_gifti, + target_density='164k', + hemi='R', + method='linear', + ) + + wd = Path(out_file) + tmp_rh = str(wd.parent / 'rh._TMP_164k_fslr.shape.gii') + tmp_lh = str(wd.parent / 'lh._TMP_164k_fslr.shape.gii') + + l_fslr[0].to_filename(tmp_lh) + r_fslr[0].to_filename(tmp_rh) + cmd = [ + 'wb_command', + '-cifti-create-dense-scalar', + '-left-metric', tmp_lh, + '-right-metric', tmp_rh, + out_file, + ] + ret = subprocess.run(cmd) + return out_file From 2ab41440b92f60d41be9d0a28477c9f5a5bc06c7 Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Wed, 4 Dec 2024 16:13:13 -0500 Subject: [PATCH 2/3] Keep working. --- src/smripost_linc/interfaces/freesurfer.py | 51 +++++++++++ src/smripost_linc/interfaces/misc.py | 98 +++++++++++++++++++++- src/smripost_linc/utils/utils.py | 79 +++++++++++++++++ src/smripost_linc/workflows/freesurfer.py | 47 ++++------- 4 files changed, 242 insertions(+), 33 deletions(-) diff --git a/src/smripost_linc/interfaces/freesurfer.py b/src/smripost_linc/interfaces/freesurfer.py index 8c80826..1984607 100644 --- a/src/smripost_linc/interfaces/freesurfer.py +++ b/src/smripost_linc/interfaces/freesurfer.py @@ -120,3 +120,54 @@ def _run_interface(self, runtime): shutil.copyfile(self.inputs.in_file, out_file) return runtime + + +class _CollectFSAverageSurfacesInputSpec(TraitedSpec): + freesurfer_dir = Directory( + exists=True, + mandatory=True, + desc='FreeSurfer directory', + ) + subject_id = traits.Str( + mandatory=True, + desc='FreeSurfer subject ID', + ) + in_file = File( + exists=True, + mandatory=True, + desc='Input annotation file', + ) + hemisphere = traits.Enum( + 'lh', + 'rh', + desc='Hemisphere to copy annotation file to', + usedefault=True, + ) + atlas = traits.Str( + desc='Atlas to used in annotation file name', + ) + + +class _CollectFSAverageSurfacesOutputSpec(TraitedSpec): + out_file = File( + exists=True, + desc='Output annotation file', + ) + + +class CollectFSAverageSurfaces(SimpleInterface): + input_spec = _CollectFSAverageSurfacesInputSpec + output_spec = _CollectFSAverageSurfacesOutputSpec + + def _run_interface(self, runtime): + out_file = os.path.join( + self.inputs.freesurfer_dir, + self.inputs.subject_id, + 'label', + f'{self.inputs.hemisphere}.{self.inputs.atlas}.annot', + ) + self._results['out_file'] = out_file + + shutil.copyfile(self.inputs.in_file, out_file) + + return runtime diff --git a/src/smripost_linc/interfaces/misc.py b/src/smripost_linc/interfaces/misc.py index 39119e2..c3a67a9 100644 --- a/src/smripost_linc/interfaces/misc.py +++ b/src/smripost_linc/interfaces/misc.py @@ -1,4 +1,6 @@ -"""Miscellaneous interfaces for fmriprep-aroma.""" +"""Miscellaneous interfaces for sMRIPost-LINC.""" + +import os import numpy as np from nipype.interfaces.base import ( @@ -17,6 +19,8 @@ _FixTraitApplyTransformsInputSpec, ) +from smripost_linc.utils.utils import split_filename + class _ApplyTransformsInputSpec(_FixTraitApplyTransformsInputSpec): # Nipype's version doesn't have GenericLabel @@ -156,6 +160,98 @@ class CiftiSeparateMetric(WBCommand): _cmd = 'wb_command -cifti-separate' +class _CiftiCreateDenseScalarInputSpec(_WBCommandInputSpec): + """Input specification for the CiftiSeparateVolumeAll command.""" + + out_file = File( + exists=False, + mandatory=False, + genfile=True, + argstr='%s', + position=0, + desc='The CIFTI output.', + ) + left_metric = File( + exists=True, + mandatory=False, + argstr='-left-metric %s', + position=1, + desc='The input surface data from the left hemisphere.', + ) + right_metric = File( + exists=True, + mandatory=False, + argstr='-right-metric %s', + position=2, + desc='The input surface data from the right hemisphere.', + ) + volume_data = File( + exists=True, + mandatory=False, + argstr='-volume %s', + position=3, + desc='The input volumetric data.', + ) + structure_label_volume = File( + exists=True, + mandatory=False, + argstr='%s', + position=4, + desc='A label file indicating the structure of each voxel in volume_data.', + ) + + +class _CiftiCreateDenseScalarOutputSpec(TraitedSpec): + """Output specification for the CiftiCreateDenseScalar command.""" + + out_file = File(exists=True, desc='output CIFTI file') + + +class CiftiCreateDenseScalar(WBCommand): + """Extract volumetric data from CIFTI file (.dtseries). + + Other structures can also be extracted. + The input cifti file must have a brain models mapping on the chosen + dimension, columns for .dtseries, + + Examples + -------- + >>> cifticreatedensescalar = CiftiCreateDenseScalar() + >>> cifticreatedensescalar.inputs.out_file = 'sub_01_task-rest.dscalar.nii' + >>> cifticreatedensescalar.inputs.left_metric = 'sub_01_task-rest_hemi-L.func.gii' + >>> cifticreatedensescalar.inputs.left_metric = 'sub_01_task-rest_hemi-R.func.gii' + >>> cifticreatedensescalar.inputs.volume_data = 'sub_01_task-rest_subcortical.nii.gz' + >>> cifticreatedensescalar.inputs.structure_label_volume = 'sub_01_task-rest_labels.nii.gz' + >>> cifticreatedensescalar.cmdline + wb_command -cifti-create-dense-scalar 'sub_01_task-rest.dscalar.nii' \ + -left-metric 'sub_01_task-rest_hemi-L.func.gii' \ + -right-metric 'sub_01_task-rest_hemi-R.func.gii' \ + -volume-data 'sub_01_task-rest_subcortical.nii.gz' 'sub_01_task-rest_labels.nii.gz' + """ + + input_spec = _CiftiCreateDenseScalarInputSpec + output_spec = _CiftiCreateDenseScalarOutputSpec + _cmd = 'wb_command -cifti-create-dense-scalar' + + def _gen_filename(self, name): + if name != 'out_file': + return None + + if isdefined(self.inputs.out_file): + return self.inputs.out_file + elif isdefined(self.inputs.volume_data): + _, fname, _ = split_filename(self.inputs.volume_data) + else: + _, fname, _ = split_filename(self.inputs.left_metric) + + return f'{fname}_converted.dscalar.nii' + + def _list_outputs(self): + outputs = self.output_spec().get() + outputs['out_file'] = os.path.abspath(self._gen_filename('out_file')) + return outputs + + class _ParcellationStats2TSVInputSpec(DynamicTraitedSpec): in_file = File(exists=True, mandatory=True, desc='parcellated data') hemisphere = traits.Enum('lh', 'rh', usedefault=True, desc='hemisphere') diff --git a/src/smripost_linc/utils/utils.py b/src/smripost_linc/utils/utils.py index 40085d0..633827c 100644 --- a/src/smripost_linc/utils/utils.py +++ b/src/smripost_linc/utils/utils.py @@ -241,3 +241,82 @@ def list_to_str(lst): return ' and '.join(lst_str) else: return f"{', '.join(lst_str[:-1])}, and {lst_str[-1]}" + + +def split_filename(fname): + """Split a filename into parts: path, base filename and extension. + + Parameters + ---------- + fname : :obj:`str` + file or path name + + Returns + ------- + pth : :obj:`str` + base path from fname + fname : :obj:`str` + filename from fname, without extension + ext : :obj:`str` + file extension from fname + + Examples + -------- + >>> from nipype.utils.filemanip import split_filename + >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz') + >>> pth + '/home/data' + + >>> fname + 'subject' + + >>> ext + '.nii.gz' + """ + # TM 07152022 - edited to add cifti and workbench extensions + special_extensions = [ + '.nii.gz', + '.tar.gz', + '.niml.dset', + '.dconn.nii', + '.dlabel.nii', + '.dpconn.nii', + '.dscalar.nii', + '.dtseries.nii', + '.fiberTEMP.nii', + '.trajTEMP.wbsparse', + '.pconn.nii', + '.pdconn.nii', + '.plabel.nii', + '.pscalar.nii', + '.ptseries.nii', + '.sdseries.nii', + '.label.gii', + '.label.gii', + '.func.gii', + '.shape.gii', + '.rgba.gii', + '.surf.gii', + '.dpconn.nii', + '.dtraj.nii', + '.pconnseries.nii', + '.pconnscalar.nii', + '.dfan.nii', + '.dfibersamp.nii', + '.dfansamp.nii', + ] + + pth = op.dirname(fname) + fname = op.basename(fname) + + ext = None + for special_ext in special_extensions: + ext_len = len(special_ext) + if (len(fname) > ext_len) and (fname[-ext_len:].lower() == special_ext.lower()): + ext = fname[-ext_len:] + fname = fname[:-ext_len] + break + if not ext: + fname, ext = op.splitext(fname) + + return pth, fname, ext diff --git a/src/smripost_linc/workflows/freesurfer.py b/src/smripost_linc/workflows/freesurfer.py index 378c654..7ebe618 100644 --- a/src/smripost_linc/workflows/freesurfer.py +++ b/src/smripost_linc/workflows/freesurfer.py @@ -7,6 +7,8 @@ from nipype.pipeline import engine as pe from niworkflows.engine.workflows import LiterateWorkflow as Workflow +from smripost_linc.interfaces.bids import DerivativesDataSink + def init_parcellate_external_wf( name_source, @@ -46,7 +48,6 @@ def init_parcellate_external_wf( parcellated_tsvs Parcellated TSV files. One for each atlas and hemisphere. """ - from smripost_linc.interfaces.bids import DerivativesDataSink from smripost_linc.interfaces.freesurfer import CopyAnnots, FreesurferFiles from smripost_linc.interfaces.misc import ParcellationStats2TSV @@ -239,6 +240,9 @@ def symlink_freesurfer_dir(freesurfer_dir, output_dir=None): def init_convert_metrics_to_cifti_wf(name='convert_metrics_to_cifti_wf'): """Convert FreeSurfer metrics from MGH format to CIFTI format in fsLR space.""" + from smripost_linc.interfaces.freesurfer import CollectFSAverageSurfaces + from smripost_linc.interfaces.misc import CiftiCreateDenseScalar + workflow = Workflow(name=name) inputnode = pe.Node( @@ -274,14 +278,14 @@ def init_convert_metrics_to_cifti_wf(name='convert_metrics_to_cifti_wf'): ) workflow.connect([ (collect_fsaverage_surfaces, convert_to_gifti, [('out_files', 'in_file')]), - (convert_to_gifti, convert_to_cifti, [('out_file', f'{hemi}_gifti')]), + (convert_to_gifti, convert_gifti_to_cifti, [('out_file', f'{hemi}_gifti')]), ]) # fmt:skip warp_fsaverage_to_fslr = pe.MapNode( niu.Function( input_names=['in_file', 'hemi'], output_names=['out_file'], - function=convert_gifti_to_cifti, + function=fsaverage_to_fslr, ), name='warp_fsaverage_to_fslr', iterfield=['in_file'], @@ -294,7 +298,6 @@ def init_convert_metrics_to_cifti_wf(name='convert_metrics_to_cifti_wf'): ds_cifti = pe.MapNode( DerivativesDataSink( - source_file=name_source, space='fsLR', extension='.dscalar.nii', ), @@ -302,48 +305,28 @@ def init_convert_metrics_to_cifti_wf(name='convert_metrics_to_cifti_wf'): iterfield=['in_file', 'suffix'], ) workflow.connect([ - (collect_fsaverage_surfaces, ds_cifti, [('names', 'in_file')]), + (collect_fsaverage_surfaces, ds_cifti, [('names', 'suffix')]), (convert_gifti_to_cifti, ds_cifti, [('out_file', 'in_file')]), ]) # fmt:skip return workflow -def convert_gifti_to_cifti(lh_gifti, rh_gifti): +def fsaverage_to_fslr(in_file, hemi): """Convert fsaverage-space GIFTI files to a CIFTI file in fsLR space.""" import os - import subprocess - from pathlib import Path - from neuromaps.transforms import fsaverage_to_fslr + from neuromaps import transforms out_file = os.path.abspath('cifti.dscalar.nii') - l_fslr = fsaverage_to_fslr( - lh_gifti, - target_density='164k', - hemi='L', - method='linear', - ) - r_fslr = fsaverage_to_fslr( - rh_gifti, + fslr_gifti = transforms.fsaverage_to_fslr( + in_file, target_density='164k', - hemi='R', + hemi=hemi[0].upper(), method='linear', ) + out_file = os.path.abspath(f'{hemi}.dscalar.nii') + fslr_gifti.to_filename(out_file) - wd = Path(out_file) - tmp_rh = str(wd.parent / 'rh._TMP_164k_fslr.shape.gii') - tmp_lh = str(wd.parent / 'lh._TMP_164k_fslr.shape.gii') - - l_fslr[0].to_filename(tmp_lh) - r_fslr[0].to_filename(tmp_rh) - cmd = [ - 'wb_command', - '-cifti-create-dense-scalar', - '-left-metric', tmp_lh, - '-right-metric', tmp_rh, - out_file, - ] - ret = subprocess.run(cmd) return out_file From 33342f92a72a9e4e398feef0b22b81e7dd0d5195 Mon Sep 17 00:00:00 2001 From: Taylor Salo Date: Thu, 5 Dec 2024 14:16:14 -0500 Subject: [PATCH 3/3] Keep working. --- src/smripost_linc/interfaces/freesurfer.py | 51 ++++++++++------------ src/smripost_linc/workflows/freesurfer.py | 6 ++- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/src/smripost_linc/interfaces/freesurfer.py b/src/smripost_linc/interfaces/freesurfer.py index 1984607..6541175 100644 --- a/src/smripost_linc/interfaces/freesurfer.py +++ b/src/smripost_linc/interfaces/freesurfer.py @@ -2,6 +2,7 @@ import os import shutil +from glob import glob from nipype.interfaces.base import ( Directory, @@ -128,30 +129,20 @@ class _CollectFSAverageSurfacesInputSpec(TraitedSpec): mandatory=True, desc='FreeSurfer directory', ) - subject_id = traits.Str( - mandatory=True, - desc='FreeSurfer subject ID', - ) - in_file = File( - exists=True, - mandatory=True, - desc='Input annotation file', - ) - hemisphere = traits.Enum( - 'lh', - 'rh', - desc='Hemisphere to copy annotation file to', - usedefault=True, - ) - atlas = traits.Str( - desc='Atlas to used in annotation file name', - ) class _CollectFSAverageSurfacesOutputSpec(TraitedSpec): - out_file = File( - exists=True, - desc='Output annotation file', + lh_fsaverage_files = traits.List( + File(exists=True), + desc='Left-hemisphere fsaverage-space surfaces', + ) + rh_fsaverage_files = traits.List( + File(exists=True), + desc='Right-hemisphere fsaverage-space surfaces', + ) + names = traits.List( + traits.Str, + desc='Names of collected surfaces', ) @@ -160,14 +151,18 @@ class CollectFSAverageSurfaces(SimpleInterface): output_spec = _CollectFSAverageSurfacesOutputSpec def _run_interface(self, runtime): - out_file = os.path.join( + in_dir = os.path.join( self.inputs.freesurfer_dir, - self.inputs.subject_id, - 'label', - f'{self.inputs.hemisphere}.{self.inputs.atlas}.annot', + 'surf', ) - self._results['out_file'] = out_file - - shutil.copyfile(self.inputs.in_file, out_file) + lh_mgh_files = sorted(glob(os.path.join(in_dir, 'lh.*.fsaverage.mgh'))) + self._results['lh_fsaverage_files'] = lh_mgh_files + self._results['names'] = [] + self._results['rh_fsaverage_files'] = [] + for lh_file in lh_mgh_files: + name = os.path.basename(lh_file).split('.')[1] + self._results['names'].append(name) + rh_file = os.path.join(in_dir, f'rh.{name}.fsaverage.mgh') + self._results['rh_fsaverage_files'].append(rh_file) return runtime diff --git a/src/smripost_linc/workflows/freesurfer.py b/src/smripost_linc/workflows/freesurfer.py index 7ebe618..d2a986a 100644 --- a/src/smripost_linc/workflows/freesurfer.py +++ b/src/smripost_linc/workflows/freesurfer.py @@ -255,7 +255,7 @@ def init_convert_metrics_to_cifti_wf(name='convert_metrics_to_cifti_wf'): name='inputnode', ) - # Convert FreeSurfer metrics to CIFTI + # Convert FreeSurfer metrics to CIFTIfy collect_fsaverage_surfaces = pe.Node( CollectFSAverageSurfaces(), name='collect_fsaverage_surfaces', @@ -277,7 +277,9 @@ def init_convert_metrics_to_cifti_wf(name='convert_metrics_to_cifti_wf'): iterfield=['in_file'], ) workflow.connect([ - (collect_fsaverage_surfaces, convert_to_gifti, [('out_files', 'in_file')]), + (collect_fsaverage_surfaces, convert_to_gifti, [ + (f'{hemi}_fsaverage_files', 'in_file'), + ]), (convert_to_gifti, convert_gifti_to_cifti, [('out_file', f'{hemi}_gifti')]), ]) # fmt:skip