Commit 5870a4f6 authored by Paul McCarthy's avatar Paul McCarthy
Browse files

featimage module unit tests. Needs more.

parent 00a64d03
......@@ -7,12 +7,14 @@
"""Unit tests for ``fslpy``. """
import os
import shutil
import tempfile
import os.path as op
import numpy as np
import nibabel as nib
import os
import glob
import shutil
import tempfile
import itertools as it
import os.path as op
import numpy as np
import nibabel as nib
def testdir(contents=None):
......@@ -102,14 +104,95 @@ def cleardir(dir):
elif op.isdir(f): shutil.rmtree(f)
def make_random_image(filename, dims=(10, 10, 10)):
def make_random_image(filename, dims=(10, 10, 10), xform=None):
"""Creates a NIFTI1 image with random data, saves and
returns it.
"""
if xform is None:
xform = np.eye(4)
data = np.array(np.random.random(dims) * 100, dtype=np.float32)
img = nib.Nifti1Image(data, np.eye(4))
img = nib.Nifti1Image(data, xform)
nib.save(img, filename)
return img
def make_mock_feat_analysis(featdir,
testdir,
shape4D,
xform=None,
indata=True,
voxEVs=True,
pes=True,
copes=True,
zstats=True,
residuals=True,
clustMasks=True):
if xform is None:
xform = np.eye(4)
timepoints = shape4D[ 3]
shape = shape4D[:3]
src = featdir
dest = op.join(testdir, op.basename(featdir))
featdir = dest
shutil.copytree(src, dest)
if indata:
filtfunc = op.join(featdir, 'filtered_func_data.nii.gz')
make_random_image(filtfunc, shape4D, xform)
# and some dummy voxelwise EV files
if voxEVs:
voxFiles = list(it.chain(
glob.glob(op.join(featdir, 'designVoxelwiseEV*nii.gz')),
glob.glob(op.join(featdir, 'InputConfoundEV*nii.gz'))))
for i, vf in enumerate(voxFiles):
# Each voxel contains range(i, i + timepoints),
# offset by the flattened voxel index
data = np.meshgrid(*[range(s) for s in shape], indexing='ij')
data = np.ravel_multi_index(data, shape)
data = data.reshape(list(shape) + [1]).repeat(timepoints, axis=3)
data[..., :] += range(i, i + timepoints)
nib.save(nib.nifti1.Nifti1Image(data, xform), vf)
otherFiles = []
otherShapes = []
if pes:
files = glob.glob(op.join(featdir, 'stats', 'pe*nii.gz'))
otherFiles .extend(files)
otherShapes.extend([shape] * len(files))
if copes:
files = glob.glob(op.join(featdir, 'stats', 'cope*nii.gz'))
otherFiles .extend(files)
otherShapes.extend([shape] * len(files))
if zstats:
files = glob.glob(op.join(featdir, 'stats', 'zstat*nii.gz'))
otherFiles .extend(files)
otherShapes.extend([shape] * len(files))
if residuals:
files = glob.glob(op.join(featdir, 'stats', 'res4d.nii.gz'))
otherFiles .extend(files)
otherShapes.extend([shape4D])
if clustMasks:
files = glob.glob(op.join(featdir, 'cluster_mask*nii.gz'))
otherFiles .extend(files)
otherShapes.extend([shape] * len(files))
for f, s in zip(otherFiles, otherShapes):
make_random_image(f, s, xform)
return featdir
......@@ -136,25 +136,17 @@ def test_FEATFSFDesign_firstLevelVoxelwiseEV(seed):
# and generate some dummy data for
# the voxelwise EVs.
featdir = op.join(testdir, '1stlevel_2.feat')
shape = (64, 64, 5)
timepoints = 45
shutil.copytree(template, featdir)
voxFiles = list(it.chain(
glob.glob(op.join(featdir, 'designVoxelwiseEV*nii.gz')),
glob.glob(op.join(featdir, 'InputConfoundEV*nii.gz'))))
for i, vf in enumerate(voxFiles):
# Each voxel contains range(i, i + timepoints),
# offset by the flattened voxel index
data = np.meshgrid(*[range(s) for s in shape], indexing='ij')
data = np.ravel_multi_index(data, shape)
data = data.reshape(list(shape) + [1]).repeat(timepoints, axis=3)
data[..., :] += range(i, i + timepoints)
fslimage.Image(data).save(vf)
shape4D = (64, 64, 5, 45)
shape = shape4D[:3]
featdir = tests.make_mock_feat_analysis(
template, testdir, shape4D,
indata=False,
pes=False,
copes=False,
zstats=False,
residuals=False,
clusterMasks=False)
# Now load the design, and make sure that
# the voxel EVs are filled correctly
......
#!/usr/bin/env python
#
# test_featimage.py -
#
# Author: Paul McCarthy <pauldmccarthy@gmail.com>
#
import os.path as op
import os
import itertools as it
import glob
import shutil
import numpy as np
import pytest
import tests
import fsl.data.featimage as featimage
import fsl.data.featdesign as featdesign
import fsl.data.featanalysis as featanalysis
datadir = op.join(op.dirname(__file__), 'testdata', 'test_feat')
featdirs = ['1stlevel_1.feat', '1stlevel_2.feat', '1stlevel_2.feat',
'2ndlevel_1.gfeat/cope1.feat', '2ndlevel_1.gfeat/cope2.feat',
'2ndlevel_2.gfeat/cope1.feat', '2ndlevel_2.gfeat/cope2.feat']
shapes = [(64, 64, 5, 45),
(64, 64, 5, 45),
(64, 64, 5, 45),
(91, 109, 91, 3),
(91, 109, 91, 3),
(91, 109, 91, 3),
(91, 109, 91, 3)]
xforms = [[[-4, 0, 0, 0],
[ 0, 4, 0, 0],
[ 0, 0, 6, 0],
[ 0, 0, 0, 1]]] * 3 + \
[[[-2, 0, 0, 90],
[ 0, 2, 0, -126],
[ 0, 0, 2, -72],
[ 0, 0, 0, 1]]] * 4
xforms = [np.array(xf) for xf in xforms]
TEST_ANALYSES = list(zip(
featdirs,
shapes,
xforms))
def test_FEATImage_attributes():
for i, featdir in enumerate(featdirs):
with tests.testdir() as testdir:
featdir = tests.make_mock_feat_analysis(
op.join(datadir, featdir),
testdir,
shapes[i],
xforms[i],
pes=False,
copes=False,
zstats=False,
residuals=False,
clustMasks=False)
# Now create a FEATImage. We validate its
# attributes against the values returned by
# the functions in featdesign/featanalysis.
fi = featimage.FEATImage(featdir)
settings = featanalysis.loadSettings(featdir)
design = featdesign.FEATFSFDesign(featdir, settings)
desmat = design.getDesign()
evnames = [ev.title for ev in design.getEVs()]
contrastnames, contrasts = featanalysis.loadContrasts(featdir)
assert fi.getFEATDir() == featdir
assert fi.getAnalysisName() == op.splitext(op.basename(featdir))[0]
assert fi.isFirstLevelAnalysis() == featanalysis.isFirstLevelAnalysis(settings)
assert fi.getTopLevelAnalysisDir() == featanalysis.getTopLevelAnalysisDir(featdir)
assert fi.getReportFile() == featanalysis.getReportFile(featdir)
assert fi.hasStats() == featanalysis.hasStats(featdir)
assert fi.numPoints() == desmat.shape[0]
assert fi.numEVs() == desmat.shape[1]
assert fi.evNames() == evnames
assert fi.numContrasts() == len(contrasts)
assert fi.contrastNames() == contrastnames
assert fi.contrasts() == contrasts
assert np.all(np.isclose(fi.getDesign(), desmat))
assert fi.thresholds() == featanalysis.getThresholds(settings)
for ci in range(len(contrasts)):
result = fi.clusterResults(ci)
expect = featanalysis.loadClusterResults(featdir, settings, ci)
assert len(result) == len(expect)
assert all([rc.nvoxels == ec.nvoxels for rc, ec in zip(result, expect)])
def test_FEATImage_imageAccessors():
for i, featdir in enumerate(featdirs):
with tests.testdir() as testdir:
featdir = tests.make_mock_feat_analysis(
op.join(datadir, featdir),
testdir,
shapes[i],
xforms[i])
shape4D = shapes[ i]
shape = shape4D[:3]
fi = featimage.FEATImage(featdir)
nevs = fi.numEVs()
ncons = fi.numContrasts()
# Testing the FEATImage intenral cache
for i in range(2):
assert fi.getResiduals().shape == shape4D
for ev in range(nevs):
assert fi.getPE(ev).shape == shape
for con in range(ncons):
assert fi.getCOPE( con).shape == shape
assert fi.getZStats( con).shape == shape
assert fi.getClusterMask(con).shape == shape
def test_FEATImage_fit_firstLevel():
featdir = ''
fi = featimage.FEATImage(featdir)
fi.fit(0, (0, 0, 0))
def test_FEATImage_fit_higherLevel():
featdir = ''
fi = featimage.FEATImage(featdir)
fi.fit(0, (0, 0, 0))
def test_FEATImage_partialFit():
featdir = ''
fi = featimage.FEATImage(featdir)
fi.fit(0, (0, 0, 0))
def test_FEATImage_nostats():
pass
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment