From 23c570e540bf0be9f1d1b97cf7883051753f02ac Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Sat, 28 Nov 2020 19:03:20 +0100 Subject: [PATCH] enh: add minimal unit test and upgrade from Function to fully-fledged interface --- sdcflows/interfaces/tests/test_utils.py | 22 +++++++++++++- sdcflows/interfaces/utils.py | 39 +++++++++++++++++++++++++ sdcflows/workflows/fit/pepolar.py | 23 +++------------ 3 files changed, 64 insertions(+), 20 deletions(-) diff --git a/sdcflows/interfaces/tests/test_utils.py b/sdcflows/interfaces/tests/test_utils.py index 231827cba7..e5715e8490 100644 --- a/sdcflows/interfaces/tests/test_utils.py +++ b/sdcflows/interfaces/tests/test_utils.py @@ -1,8 +1,9 @@ """Test utilites.""" +import pytest import numpy as np import nibabel as nb -from ..utils import Flatten +from ..utils import Flatten, ConvertWarp def test_Flatten(tmpdir): @@ -31,3 +32,22 @@ def test_Flatten(tmpdir): assert out_meta[0] == {"a": 1} assert out_meta[1] == out_meta[2] == out_meta[3] == {"b": 2} assert out_meta[4] == out_meta[5] == {"c": 3} + + +@pytest.mark.parametrize("shape", [ + (10, 10, 10, 1, 3), + (10, 10, 10, 3) +]) +def test_ConvertWarp(tmpdir, shape): + """Exercise the interface.""" + tmpdir.chdir() + + nb.Nifti1Image(np.zeros(shape, dtype="uint8"), + np.eye(4), None).to_filename("3dQwarp.nii.gz") + + out = ConvertWarp(in_file="3dQwarp.nii.gz").run() + + nii = nb.load(out.outputs.out_file) + assert nii.header.get_data_dtype() == np.float32 + assert nii.header.get_intent() == ("vector", (), "") + assert nii.shape == (10, 10, 10, 1, 3) diff --git a/sdcflows/interfaces/utils.py b/sdcflows/interfaces/utils.py index f1d1127aca..7d0200b6ed 100644 --- a/sdcflows/interfaces/utils.py +++ b/sdcflows/interfaces/utils.py @@ -50,6 +50,27 @@ def _run_interface(self, runtime): return runtime +class _ConvertWarpInputSpec(BaseInterfaceInputSpec): + in_file = File(exists=True, mandatory=True, desc="output of 3dQwarp") + + +class _ConvertWarpOutputSpec(TraitedSpec): + out_file = File(exists=True, desc="the warp converted into ANTs") + + +class ConvertWarp(SimpleInterface): + """Convert a displacements field from ``3dQwarp`` to ANTS-compatible.""" + + input_spec = _ConvertWarpInputSpec + output_spec = _ConvertWarpOutputSpec + + def _run_interface(self, runtime): + self._results["out_file"] = _qwarp2ants( + self.inputs.in_file, newpath=runtime.cwd + ) + return runtime + + def _flatten(inlist, max_trs=50, out_dir=None): """ Split the input EPIs and generate a flattened list with corresponding metadata. @@ -83,3 +104,21 @@ def _flatten(inlist, max_trs=50, out_dir=None): output.append((str(out_name), meta)) return output + + +def _qwarp2ants(in_file, newpath=None): + """Ensure the data type and intent of a warp is acceptable by ITK-based tools.""" + import numpy as np + import nibabel as nb + from nipype.utils.filemanip import fname_presuffix + + nii = nb.load(in_file) + hdr = nii.header.copy() + hdr.set_data_dtype("