diff --git a/sdcflows/interfaces/bspline.py b/sdcflows/interfaces/bspline.py index ccb9ad3c7f..6292a4199d 100644 --- a/sdcflows/interfaces/bspline.py +++ b/sdcflows/interfaces/bspline.py @@ -327,7 +327,18 @@ class _TOPUPCoeffReorientInputSpec(BaseInterfaceInputSpec): File(exist=True), mandatory=True, desc="input coefficients file(s) from TOPUP" ) fmap_ref = File(exists=True, mandatory=True, desc="the fieldmap reference") - + pe_dir = traits.Enum( + "+", + "-", + "i", + "i-", + "j", + "j-", + "k", + "k-", + usedefault=True, + desc="the polarity of the phase-encoding direction corresponding to fmap_ref", + ) class _TOPUPCoeffReorientOutputSpec(TraitedSpec): out_coeff = OutputMultiObject(File(exists=True), desc="patched coefficients") @@ -368,7 +379,8 @@ def _run_interface(self, runtime): _fix_topup_fieldcoeff( in_coeff, self.inputs.fmap_ref, - fname_presuffix(in_coeff, suffix="_fixed", newpath=runtime.cwd), + refpe_reversed=self.inputs.pe_dir.endswith("-"), + out_file=fname_presuffix(in_coeff, suffix="_fixed", newpath=runtime.cwd), ) ) for in_coeff in self.inputs.in_coeff @@ -598,7 +610,7 @@ def _move_coeff(in_coeff, fmap_ref, transform): return out -def _fix_topup_fieldcoeff(in_coeff, fmap_ref, out_file=None): +def _fix_topup_fieldcoeff(in_coeff, fmap_ref, refpe_reversed=False, out_file=None): """Read in a coefficients file generated by TOPUP and fix x-form headers.""" from pathlib import Path import numpy as np @@ -627,5 +639,7 @@ def _fix_topup_fieldcoeff(in_coeff, fmap_ref, out_file=None): coeffnii.header.set_qform(coeffnii.header.get_qform(coded=False), code=0) coeffnii.header.set_sform(newaff, code=1) - coeffnii.__class__(coeffnii.dataobj, newaff, header).to_filename(out_file) + # If the reference is reversed encoded, flip the displacements + coeffs = (1.0 - 2.0 * refpe_reversed) * np.asanyarray(coeffnii.dataobj) + coeffnii.__class__(coeffs, newaff, header).to_filename(out_file) return out_file diff --git a/sdcflows/workflows/fit/pepolar.py b/sdcflows/workflows/fit/pepolar.py index b78fd49283..c0ea10eda2 100644 --- a/sdcflows/workflows/fit/pepolar.py +++ b/sdcflows/workflows/fit/pepolar.py @@ -72,6 +72,7 @@ def init_topup_wf(omp_nthreads=1, sloppy=False, debug=False, name="pepolar_estim from niworkflows.interfaces.nibabel import MergeSeries from niworkflows.interfaces.images import IntraModalMerge + from ...utils.misc import front as _front from ...interfaces.epi import GetReadoutTime from ...interfaces.utils import Flatten from ...interfaces.bspline import TOPUPCoeffReorient @@ -125,6 +126,11 @@ def init_topup_wf(omp_nthreads=1, sloppy=False, debug=False, name="pepolar_estim brainextraction_wf = init_brainextraction_wf() + def _getpe(in_meta): + if isinstance(in_meta, list): + in_meta = in_meta[0] + return in_meta["PhaseEncodingDirection"] + # fmt: off workflow.connect([ (inputnode, flatten, [("in_data", "in_data"), @@ -135,9 +141,10 @@ def init_topup_wf(omp_nthreads=1, sloppy=False, debug=False, name="pepolar_estim (flatten, topup, [(("out_meta", _pe2fsl), "encoding_direction")]), (readout_time, topup, [("readout_time", "readout_times")]), (concat_blips, topup, [("out_file", "in_file")]), + (flatten, fix_coeff, [(("out_data", _front), "fmap_ref"), + (("out_meta", _getpe), "pe_dir")]), + (topup, fix_coeff, [("out_fieldcoef", "in_coeff")]), (topup, merge_corrected, [("out_corrected", "in_files")]), - (topup, fix_coeff, [("out_fieldcoef", "in_coeff"), - ("out_corrected", "fmap_ref")]), (topup, outputnode, [("out_field", "fmap"), ("out_jacs", "jacobians"), ("out_mats", "xfms"),