Skip to content

Commit 7b02c72

Browse files
author
bpinsard
committed
Merge branch 'master' into enh/vbm
* master: (24 commits) Doctests fix Fixed tests. in fact masking wasn't working, HistogramRegistration takes mask as numpy not nibabel allow similarity computation without mask Added [xor] metadata to afni.AutoTcorrelate added mask_source option to afni.AutoTcorrelate added mask_source option to afni.AutoTcorrelate fix fugue for not necessarly wanted output fix forward_warping input add Complex to __init__.py fix Complex doc fslcomplex interface + fix line removed inadvertently adding doctest to sigloss typo fixing abspath bug bugfix abspath added SigLoss to __init__ added fsl sigloss to utils allow FUGUE to run without in_file allow FUGUE to run without in_file ...
2 parents c8f6947 + d486984 commit 7b02c72

File tree

9 files changed

+241
-70
lines changed

9 files changed

+241
-70
lines changed

nipype/interfaces/afni/preprocess.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,13 @@ class AutoTcorrelateInputSpec(AFNICommandInputSpec):
320320
mask = File(exists=True, desc="mask of voxels",
321321
argstr="-mask %s")
322322
mask_only_targets = traits.Bool(desc="use mask only on targets voxels",
323-
argstr="-mask_only_targets")
323+
argstr="-mask_only_targets",
324+
xor=['mask_source'])
325+
326+
mask_source = File(exists=True,
327+
desc="mask for source voxels",
328+
argstr="-mask_source %s",
329+
xor=['mask_only_targets'])
324330

325331
out_file = File("%s_similarity_matrix.1D", desc='output image file name',
326332
argstr='-prefix %s', name_source="in_file", usedefault=True)

nipype/interfaces/afni/tests/test_preprocess.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def test_allineate():
1818
environ = dict(usedefault=True,),
1919
ignore_exception = dict(usedefault=True,),
2020
in_file = dict(argstr='-source %s',mandatory=True,),
21-
matrix = dict(argstr='-1dmatrix_apply %s',),
21+
in_matrix = dict(argstr='-1Dmatrix_apply %s',),
2222
out_file = dict(argstr='-prefix %s'),
2323
outputtype = dict(),
2424
)

nipype/interfaces/fsl/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
from .utils import (Smooth, Merge, ExtractROI, Split, ImageMaths, ImageMeants,
1616
ImageStats, FilterRegressor, Overlay, Slicer,
1717
PlotTimeSeries, PlotMotionParams, ConvertXFM,
18-
SwapDimensions, PowerSpectrum, Reorient2Std)
18+
SwapDimensions, PowerSpectrum, SigLoss, Reorient2Std,
19+
Complex)
1920
from .dti import (EddyCorrect, BEDPOSTX, DTIFit, ProbTrackX, VecReg, ProjThresh,
2021
FindTheBiggest, DistanceMap, TractSkeleton, XFibres,
2122
MakeDyadicVectors)

nipype/interfaces/fsl/preprocess.py

Lines changed: 45 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,14 +1188,15 @@ def _gen_filename(self, name):
11881188
class FUGUEInputSpec(FSLCommandInputSpec):
11891189
in_file = File(exists=True, argstr='--in=%s',
11901190
desc='filename of input volume')
1191-
unwarped_file = File(argstr='--unwarp=%s', genfile=True,
1192-
desc='apply unwarping and save as filename', hash_files=False)
1193-
1194-
save_warped = traits.Bool(desc='apply forward warp and save')
1195-
1196-
warped_file = File(argstr='--warp=%s', genfile=True,
1197-
desc='apply forward warp and save as filename', hash_files=False)
1198-
1191+
unwarped_file = File(
1192+
argstr='--unwarp=%s', genfile=True,
1193+
desc='apply unwarping and save as filename', hash_files=False)
1194+
forward_warping = traits.Bool(
1195+
False, usedefault=True,
1196+
desc='apply forward warping instead of unwarping')
1197+
warped_file = File(argstr='--warp=%s',
1198+
desc='apply forward warping and save as filename',
1199+
hash_files=False)
11991200
phasemap_file = File(exists=True, argstr='--phasemap=%s',
12001201
desc='filename for input phase image')
12011202
dwell_to_asym_ratio = traits.Float(argstr='--dwelltoasym=%.10f',
@@ -1211,7 +1212,7 @@ class FUGUEInputSpec(FSLCommandInputSpec):
12111212

12121213
save_shift = traits.Bool(desc='output pixel shift volume')
12131214

1214-
shift_out_file = traits.File(argstr='--saveshift=%s', genfile=True,
1215+
shift_out_file = traits.File(argstr='--saveshift=%s',
12151216
desc='filename for saving pixel shift volume', hash_files=False)
12161217

12171218
shift_in_file = File(exists=True, argstr='--loadshift=%s',
@@ -1247,25 +1248,20 @@ class FUGUEInputSpec(FSLCommandInputSpec):
12471248
desc='apply intensity correction only')
12481249
mask_file = File(exists=True, argstr='--mask=%s',
12491250
desc='filename for loading valid mask')
1250-
save_unmasked_fmap = traits.Either(traits.Bool,
1251-
traits.File,
1252-
argstr='--unmaskfmap=%s',
1253-
requires=['fmap_out_file'],
1254-
desc='saves the unmasked fieldmap when using --savefmap', hash_files=False)
1255-
save_unmasked_shift = traits.Either(traits.Bool,
1256-
traits.File,
1257-
argstr='--unmaskshift=%s',
1258-
requires=['shift_out_file'],
1259-
desc='saves the unmasked shiftmap when using --saveshift', hash_files=False)
1260-
nokspace = traits.Bool(
1261-
argstr='--nokspace', desc='do not use k-space forward warping')
1251+
save_unmasked_fmap = traits.Bool(argstr='--unmaskfmap',
1252+
requires=['fmap_out_file'],
1253+
desc='saves the unmasked fieldmap when using --savefmap')
1254+
save_unmasked_shift = traits.Bool(argstr='--unmaskshift',
1255+
requires=['shift_out_file'],
1256+
desc='saves the unmasked shiftmap when using --saveshift')
1257+
nokspace = traits.Bool(argstr='--nokspace', desc='do not use k-space forward warping')
12621258

12631259

12641260
class FUGUEOutputSpec(TraitedSpec):
1265-
unwarped_file = File(exists=True, desc='unwarped file')
1261+
unwarped_file = File(desc='unwarped file')
1262+
warped_file = File(desc='forward warped file')
12661263
shift_out_file = File(desc='voxel shift map file')
1267-
warped_file = File(desc='warped file')
1268-
1264+
fmap_out_file = File(desc='fieldmap file')
12691265

12701266
class FUGUE(FSLCommand):
12711267
"""Use FSL FUGUE to unwarp epi's with fieldmaps
@@ -1299,43 +1295,40 @@ def _parse_inputs(self, skip=None):
12991295

13001296
def _list_outputs(self):
13011297
outputs = self._outputs().get()
1302-
out_file = self.inputs.unwarped_file
1303-
if not isdefined(out_file):
1304-
out_file = self._gen_fname(self.inputs.in_file,
1305-
suffix='_unwarped')
1306-
outputs['unwarped_file'] = os.path.abspath(out_file)
1307-
1308-
if isdefined(self.inputs.save_shift) and self.inputs.save_shift:
1309-
shift_out = self.inputs.shift_out_file
1310-
if not isdefined(shift_out):
1311-
shift_out = self._gen_fname(
1312-
self.inputs.in_file, suffix='_shift')
1298+
if self.inputs.forward_warping:
1299+
out_field = 'warped_file'
1300+
else:
1301+
out_field = 'unwarped_file'
13131302

1314-
outputs['shift_out_file'] = os.path.abspath(shift_out)
1315-
1316-
if isdefined(self.inputs.save_warped) and self.inputs.save_warped:
1317-
warped_out = self.inputs.warped_file
1318-
if not isdefined(warped_out):
1319-
warped_out = self._gen_fname(
1320-
self.inputs.in_file, suffix='_fwdwarp')
1321-
1322-
outputs['warped_file'] = os.path.abspath(warped_out)
1323-
del outputs['unwarped_file']
1303+
out_file = getattr(self.inputs,out_field)
1304+
if not isdefined(out_file):
1305+
if isdefined(self.inputs.in_file):
1306+
out_file = self._gen_fname(self.inputs.in_file,
1307+
suffix='_'+out_field[:-5])
1308+
if isdefined(out_file):
1309+
outputs[out_field] = os.path.abspath(out_file)
1310+
if isdefined(self.inputs.fmap_out_file):
1311+
outputs['fmap_out_file'] = os.path.abspath(self.inputs.fmap_out_file)
1312+
if isdefined(self.inputs.shift_out_file):
1313+
outputs['shift_out_file'] = os.path.abspath(self.inputs.shift_out_file)
13241314

13251315
return outputs
13261316

13271317
def _gen_filename(self, name):
1328-
if name == 'unwarped_file':
1318+
if name == 'unwarped_file' and not self.inputs.forward_warping:
13291319
return self._list_outputs()['unwarped_file']
1330-
1331-
if name == 'warped_file':
1320+
if name == 'warped_file' and self.inputs.forward_warping:
13321321
return self._list_outputs()['warped_file']
1333-
1334-
if name == 'shift_out_file':
1335-
return self._list_outputs()['shift_out_file']
1336-
13371322
return None
13381323

1324+
def _parse_inputs(self,skip=None):
1325+
if skip==None:
1326+
skip=[]
1327+
if self.inputs.forward_warping or not isdefined(self.inputs.in_file):
1328+
skip+=['unwarped_file']
1329+
if not self.inputs.forward_warping or not isdefined(self.inputs.in_file):
1330+
skip+=['warped_file']
1331+
return super(FUGUE,self)._parse_inputs(skip=skip)
13391332

13401333
class PRELUDEInputSpec(FSLCommandInputSpec):
13411334
complex_phase_file = File(exists=True, argstr='--complex=%s',

nipype/interfaces/fsl/tests/test_preprocess.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -503,8 +503,8 @@ def test_fugue():
503503
phase_conjugate = dict(argstr='--phaseconj',),
504504
phasemap_file = dict(argstr='--phasemap=%s',),
505505
poly_order = dict(argstr='--poly=%d',),
506-
save_unmasked_fmap = dict(requires=['fmap_out_file'],argstr='--unmaskfmap=%s',),
507-
save_unmasked_shift = dict(requires=['shift_out_file'],argstr='--unmaskshift=%s',),
506+
save_unmasked_fmap = dict(requires=['fmap_out_file'],argstr='--unmaskfmap',),
507+
save_unmasked_shift = dict(requires=['shift_out_file'],argstr='--unmaskshift',),
508508
shift_in_file = dict(argstr='--loadshift=%s',),
509509
shift_out_file = dict(argstr='--saveshift=%s',),
510510
smooth2d = dict(argstr='--smooth2=%.2f',),

nipype/interfaces/fsl/utils.py

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,6 +1152,54 @@ def _list_outputs(self):
11521152
basename='maskexf')
11531153
return outputs
11541154

1155+
class SigLossInputSpec(FSLCommandInputSpec):
1156+
in_file = File(mandatory=True,
1157+
exists=True,
1158+
argstr='-i %s',
1159+
desc='b0 fieldmap file')
1160+
out_file = File(argstr='-s %s',
1161+
desc='output signal loss estimate file',
1162+
genfile=True)
1163+
1164+
mask_file = File(exists=True,
1165+
argstr='-m %s',
1166+
desc='brain mask file')
1167+
echo_time = traits.Float(argstr='--te=%f',
1168+
desc='echo time in seconds')
1169+
slice_direction = traits.Enum('x','y','z',
1170+
argstr='-d %s',
1171+
desc='slicing direction')
1172+
class SigLossOuputSpec(TraitedSpec):
1173+
out_file = File(exists=True,
1174+
desc='signal loss estimate file')
1175+
1176+
class SigLoss(FSLCommand):
1177+
"""Estimates signal loss from a field map (in rad/s)
1178+
1179+
Examples
1180+
--------
1181+
>>> sigloss = SigLoss()
1182+
>>> sigloss.inputs.in_file = "phase.nii"
1183+
>>> sigloss.inputs.echo_time = 0.03
1184+
>>> res = sigloss.run() # doctest: +SKIP
1185+
"""
1186+
input_spec = SigLossInputSpec
1187+
output_spec = SigLossOuputSpec
1188+
_cmd = 'sigloss'
1189+
1190+
def _list_outputs(self):
1191+
outputs = self.output_spec().get()
1192+
outputs['out_file'] = self.inputs.out_file
1193+
if not isdefined(outputs['out_file']) and isdefined(self.inputs.in_file):
1194+
outputs['out_file']=self._gen_fname(self.inputs.in_file,
1195+
suffix='_sigloss')
1196+
return outputs
1197+
1198+
def _gen_filename(self, name):
1199+
if name=='out_file':
1200+
return self._list_outputs()['out_file']
1201+
return None
1202+
11551203
class Reorient2StdInputSpec(FSLCommandInputSpec):
11561204
in_file = File(exists=True, mandatory=True, argstr="%s")
11571205
out_file = File(genfile=True, hash_files=False, argstr="%s")
@@ -1188,3 +1236,130 @@ def _list_outputs(self):
11881236
else:
11891237
outputs['out_file'] = os.path.abspath(self.inputs.out_file)
11901238
return outputs
1239+
1240+
1241+
class ComplexInputSpec(FSLCommandInputSpec):
1242+
complex_in_file = File(exists=True, argstr="%s", position=2)
1243+
complex_in_file2 = File(exists=True, argstr="%s", position=3)
1244+
1245+
real_in_file = File(exists=True, argstr="%s", position=2)
1246+
imaginary_in_file = File(exists=True, argstr="%s", position=3)
1247+
magnitude_in_file = File(exists=True, argstr="%s", position=2)
1248+
phase_in_file = File(exists=True, argstr='%s', position=3)
1249+
1250+
_ofs = ['complex_out_file',
1251+
'magnitude_out_file','phase_out_file',
1252+
'real_out_file','imaginary_out_file']
1253+
_conversion = ['real_polar','real_cartesian',
1254+
'complex_cartesian','complex_polar',
1255+
'complex_split','complex_merge',]
1256+
1257+
complex_out_file = File(genfile=True, argstr="%s", position=-3,
1258+
xor=_ofs+_conversion[:2])
1259+
magnitude_out_file = File(genfile=True, argstr="%s", position=-4,
1260+
xor=_ofs[:1]+_ofs[3:]+_conversion[1:])
1261+
phase_out_file = File(genfile=True, argstr="%s", position=-3,
1262+
xor=_ofs[:1]+_ofs[3:]+_conversion[1:])
1263+
real_out_file = File(genfile=True, argstr="%s", position=-4,
1264+
xor=_ofs[:3]+_conversion[:1]+_conversion[2:])
1265+
imaginary_out_file = File(genfile=True, argstr="%s", position=-3,
1266+
xor=_ofs[:3]+_conversion[:1]+_conversion[2:])
1267+
1268+
start_vol = traits.Int(position=-2, argstr='%d')
1269+
end_vol = traits.Int(position=-1, argstr='%d')
1270+
1271+
real_polar = traits.Bool(
1272+
argstr = '-realpolar', xor = _conversion, position=1,)
1273+
# requires=['complex_in_file','magnitude_out_file','phase_out_file'])
1274+
real_cartesian = traits.Bool(
1275+
argstr = '-realcartesian', xor = _conversion, position=1,)
1276+
# requires=['complex_in_file','real_out_file','imaginary_out_file'])
1277+
complex_cartesian = traits.Bool(
1278+
argstr = '-complex', xor = _conversion, position=1,)
1279+
# requires=['real_in_file','imaginary_in_file','complex_out_file'])
1280+
complex_polar = traits.Bool(
1281+
argstr = '-complexpolar', xor = _conversion, position=1,)
1282+
# requires=['magnitude_in_file','phase_in_file',
1283+
# 'magnitude_out_file','phase_out_file'])
1284+
complex_split = traits.Bool(
1285+
argstr = '-complexsplit', xor = _conversion, position=1,)
1286+
# requires=['complex_in_file','complex_out_file'])
1287+
complex_merge = traits.Bool(
1288+
argstr = '-complexmerge', xor = _conversion + ['start_vol','end_vol'],
1289+
position=1,)
1290+
# requires=['complex_in_file','complex_in_file2','complex_out_file'])
1291+
1292+
class ComplexOuputSpec(TraitedSpec):
1293+
magnitude_out_file = File()
1294+
phase_out_file = File()
1295+
real_out_file = File()
1296+
imaginary_out_file = File()
1297+
complex_out_file = File()
1298+
1299+
1300+
class Complex(FSLCommand):
1301+
"""fslcomplex is a tool for converting complex data
1302+
Examples
1303+
--------
1304+
>>> cplx = Complex()
1305+
>>> cplx.inputs.complex_in_file = "complex.nii"
1306+
>>> cplx.real_polar = True
1307+
>>> res = cplx.run() # doctest: +SKIP
1308+
1309+
"""
1310+
_cmd = 'fslcomplex'
1311+
input_spec = ComplexInputSpec
1312+
output_spec = ComplexOuputSpec
1313+
1314+
def _parse_inputs(self, skip=None):
1315+
if skip == None:
1316+
skip = []
1317+
if self.inputs.real_cartesian:
1318+
skip += self.inputs._ofs[:3]
1319+
elif self.inputs.real_polar:
1320+
skip += self.inputs._ofs[:1]+self.inputs._ofs[3:]
1321+
else:
1322+
skip += self.inputs._ofs[1:]
1323+
return super(Complex,self)._parse_inputs(skip)
1324+
1325+
def _gen_filename(self, name):
1326+
if name == 'complex_out_file':
1327+
if self.inputs.complex_cartesian:
1328+
in_file = self.inputs.real_in_file
1329+
elif self.inputs.complex_polar:
1330+
in_file = self.inputs.magnitude_in_file
1331+
elif self.inputs.complex_split or self.inputs.complex_merge:
1332+
in_file = self.inputs.complex_in_file
1333+
else:
1334+
return None
1335+
return self._gen_fname(in_file, suffix="_cplx")
1336+
elif name =='magnitude_out_file':
1337+
return self._gen_fname(self.inputs.complex_in_file, suffix="_mag")
1338+
elif name =='phase_out_file':
1339+
return self._gen_fname(self.inputs.complex_in_file,suffix="_phase")
1340+
elif name =='real_out_file':
1341+
return self._gen_fname(self.inputs.complex_in_file, suffix="_real")
1342+
elif name =='imaginary_out_file':
1343+
return self._gen_fname(self.inputs.complex_in_file, suffix="_imag")
1344+
return None
1345+
1346+
def _get_output(self,name):
1347+
output = getattr(self.inputs,name)
1348+
if not isdefined(output):
1349+
output = self._gen_filename(name)
1350+
return os.path.abspath(output)
1351+
1352+
def _list_outputs(self):
1353+
outputs = self.output_spec().get()
1354+
if self.inputs.complex_cartesian or self.inputs.complex_polar or \
1355+
self.inputs.complex_split or self.inputs.complex_merge:
1356+
outputs['complex_out_file'] = self._get_output('complex_out_file')
1357+
elif self.inputs.real_cartesian:
1358+
outputs['real_out_file'] = self._get_output('real_out_file')
1359+
outputs['imaginary_out_file'] = self._get_output('imaginary_out_file')
1360+
elif self.inputs.real_polar:
1361+
outputs['magnitude_out_file'] = self._get_output('magnitude_out_file')
1362+
outputs['phase_out_file'] = self._get_output('phase_out_file')
1363+
return outputs
1364+
1365+

0 commit comments

Comments
 (0)