Skip to content

WIP: Adding a python wrapper for ICA_AROMA #1993

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

Merged
merged 11 commits into from
May 10, 2017
118 changes: 118 additions & 0 deletions nipype/interfaces/fsl/ICA_AROMA.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# -*- coding: utf-8 -*-
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
# vi: set ft=python sts=4 ts=4 sw=4 et:
"""This commandline module provides classes for interfacing with the
`ICA-AROMA.py<https://github.com/rhr-pruim/ICA-AROMA>`_ command line tool.
Change directory to provide relative paths for doctests
>>> import os
>>> filepath = os.path.dirname(os.path.realpath(__file__))
>>> datadir = os.path.realpath(os.path.join(filepath,
... '../../testing/data'))
>>> os.chdir(datadir)
"""
from nipype.interfaces.base import (
TraitedSpec,
CommandLineInputSpec,
CommandLine,
File,
Directory,
traits,
OutputMultiPath
)
import os

class ICA_AROMAInputSpec(CommandLineInputSpec):
feat_dir = Directory(exists=True, mandatory=True,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think feat_dir is mandatory in ICA AROMA.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

feat_dir or in_file and friends. xor handles competing mandatory=True traits.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh ok - sorry!

argstr='-feat %s',
xor=['in_file', 'mat_file', 'fnirt_warp_file', 'motion_parameters'],
desc='If a feat directory exists and temporal filtering '
'has not been run yet, ICA_AROMA can use the files in '
'this directory.')
in_file = File(exists=True, mandatory=True,
argstr='-i %s', xor=['feat_dir'],
desc='volume to be denoised')
out_dir = Directory('out', mandatory=True,
argstr='-o %s',
desc='output directory')
mask = File(exists=True, argstr='-m %s', xor=['feat_dir'],
desc='path/name volume mask')
dim = traits.Int(argstr='-dim %d',
desc='Dimensionality reduction when running '
'MELODIC (defualt is automatic estimation)')
TR = traits.Float(argstr='-tr %.3f',
desc='TR in seconds. If this is not specified '
'the TR will be extracted from the '
'header of the fMRI nifti file.')
melodic_dir = Directory(exists=True, argstr='-meldir %s',
desc='path to MELODIC directory if MELODIC has already been run')
mat_file = File(exists=True, argstr='-affmat %s', xor=['feat_dir'],
desc='path/name of the mat-file describing the '
'affine registration (e.g. FSL FLIRT) of the '
'functional data to structural space (.mat file)')
fnirt_warp_file = File(exists=True, argstr='-warp %s', xor=['feat_dir'],
desc='File name of the warp-file describing '
'the non-linear registration (e.g. FSL FNIRT) '
'of the structural data to MNI152 space (.nii.gz)')
motion_parameters = File(exists=True, mandatory=True,
argstr='-mc %s', xor=['feat_dir'],
desc='motion parameters file')
denoise_type = traits.Enum('nonaggr', 'aggr', 'both', 'no', usedefault=True,
mandatory=True, argstr='-den %s',
desc='Type of denoising strategy:\n'
'-none: only classification, no denoising\n'
'-nonaggr (default): non-aggresssive denoising, i.e. partial component regression\n'
'-aggr: aggressive denoising, i.e. full component regression\n'
'-both: both aggressive and non-aggressive denoising (two outputs)')

class ICA_AROMAOutputSpec(TraitedSpec):
aggr_denoised_file = File(exists=True,
desc='if generated: aggressively denoised volume')
nonaggr_denoised_file = File(exists=True,
desc='if generated: non aggressively denoised volume' )
out_dir = Directory(exists=True,
desc='directory contains (in addition to the denoised files): '
'melodic.ica + classified_motion_components + '
'classification_overview + feature_scores + melodic_ic_mni)')

class ICA_AROMA(CommandLine):
"""
Interface for the ICA_AROMA.py script.

ICA-AROMA (i.e. 'ICA-based Automatic Removal Of Motion Artifacts') concerns
a data-driven method to identify and remove motion-related independent
components from fMRI data. To that end it exploits a small, but robust
set of theoretically motivated features, preventing the need for classifier
re-training and therefore providing direct and easy applicability.

See link for further documentation: https://github.com/rhr-pruim/ICA-AROMA

Example
-------

>>> from nipype.interfaces.fsl import ICA_AROMA
>>> from nipype.testing import example_data
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can remove the example_data import. Shouldn't have any effect on the tests, though.

>>> AROMA_obj = ICA_AROMA.ICA_AROMA()
>>> AROMA_obj.inputs.in_file = 'functional.nii'
>>> AROMA_obj.inputs.mat_file = 'func_to_struct.mat'
>>> AROMA_obj.inputs.fnirt_warp_file = 'warpfield.nii'
>>> AROMA_obj.inputs.motion_parameters = 'fsl_mcflirt_movpar.txt'
>>> AROMA_obj.inputs.mask = 'mask.nii.gz'
>>> AROMA_obj.inputs.denoise_type = 'both'
>>> AROMA_obj.inputs.out_dir = 'ICA_testout'
>>> AROMA_obj.cmdline # doctest: +ALLOW_UNICODE
'ICA_AROMA.py -den both -warp warpfield.nii -i functional.nii -m mask.nii.gz -affmat func_to_struct.mat -mc fsl_mcflirt_movpar.txt -o ICA_testout'
"""
_cmd = 'ICA_AROMA.py'
input_spec = ICA_AROMAInputSpec
output_spec = ICA_AROMAOutputSpec

def _list_outputs(self):
out_dir = os.path.abspath(self.inputs.out_dir)
outputs['out_dir'] = out_dir

if self.inputs.denoise_type in ('aggr', 'both'):
outputs['aggr_denoised_file'] = os.path.join(out_dir, 'denoised_func_data_aggr.nii.gz')
if self.inputs.denoise_type in ('nonaggr', 'both'):
outputs['nonaggr_denoised_file'] = os.path.join(out_dir, 'denoised_func_data_nonaggr.nii.gz')

return outputs
68 changes: 68 additions & 0 deletions nipype/interfaces/fsl/tests/test_auto_ICA_AROMA.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# AUTO-GENERATED by tools/checkspecs.py - DO NOT EDIT
from __future__ import unicode_literals
from ..ICA_AROMA import ICA_AROMA


def test_ICA_AROMA_inputs():
input_map = dict(TR=dict(argstr='-tr %.3f',
),
args=dict(argstr='%s',
),
denoise_type=dict(argstr='-den %s',
mandatory=True,
usedefault=True,
),
dim=dict(argstr='-dim %d',
),
environ=dict(nohash=True,
usedefault=True,
),
feat_dir=dict(argstr='-feat %s',
mandatory=True,
xor=['in_file', 'mat_file', 'fnirt_warp_file', 'motion_parameters'],
),
fnirt_warp_file=dict(argstr='-warp %s',
xor=['feat_dir'],
),
ignore_exception=dict(nohash=True,
usedefault=True,
),
in_file=dict(argstr='-i %s',
mandatory=True,
xor=['feat_dir'],
),
mask=dict(argstr='-m %s',
xor=['feat_dir'],
),
mat_file=dict(argstr='-affmat %s',
xor=['feat_dir'],
),
melodic_dir=dict(argstr='-meldir %s',
),
motion_parameters=dict(argstr='-mc %s',
mandatory=True,
xor=['feat_dir'],
),
out_dir=dict(argstr='-o %s',
mandatory=True,
),
terminal_output=dict(nohash=True,
),
)
inputs = ICA_AROMA.input_spec()

for key, metadata in list(input_map.items()):
for metakey, value in list(metadata.items()):
assert getattr(inputs.traits()[key], metakey) == value


def test_ICA_AROMA_outputs():
output_map = dict(aggr_denoised_file=dict(),
nonaggr_denoised_file=dict(),
out_dir=dict(),
)
outputs = ICA_AROMA.output_spec()

for key, metadata in list(output_map.items()):
for metakey, value in list(metadata.items()):
assert getattr(outputs.traits()[key], metakey) == value