Repository: nipy/nipype

Issue:
ENH: improve sdc_fmb (fieldmap-based susceptibility distortion correction)
- [x] Replace flirt by antsRegistration
- [x] Execute workflow with HCP data
- [x] Write parameters in docstrings
- [x] Read parameters from JSON file (?), instead of getting them as arguments (requires #1020)
- [x] Set default parameters (requires #1047)
- [x] Update workflows depending on `sdc_fmb`



Discussion:

Resolving patch:
diff --git a/nipype/workflows/dmri/fsl/artifacts.py b/nipype/workflows/dmri/fsl/artifacts.py
--- a/nipype/workflows/dmri/fsl/artifacts.py
+++ b/nipype/workflows/dmri/fsl/artifacts.py
@@ -1,23 +1,18 @@
 # 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:
-
-import nipype.pipeline.engine as pe
-import nipype.interfaces.utility as niu
-import nipype.interfaces.fsl as fsl
-import nipype.interfaces.freesurfer as fs
-import nipype.interfaces.ants as ants
 import os
 
+import nipype.pipeline.engine as pe
+from nipype.interfaces.io import JSONFileGrabber
+from nipype.interfaces import utility as niu
+from nipype.interfaces import freesurfer as fs
+from nipype.interfaces import ants
+from nipype.interfaces import fsl
 from .utils import *
 
 
-def all_fmb_pipeline(name='hmc_sdc_ecc',
-                     fugue_params=dict(smooth3d=2.0),
-                     bmap_params=dict(delta_te=2.46e-3),
-                     epi_params=dict(echospacing=0.77e-3,
-                                     acc_factor=3,
-                                     enc_dir='y-')):
+def all_fmb_pipeline(name='hmc_sdc_ecc', fugue_params=dict(smooth3d=2.0)):
     """
     Builds a pipeline including three artifact corrections: head-motion
     correction (HMC), susceptibility-derived distortion correction (SDC),
@@ -40,28 +35,35 @@ def all_fmb_pipeline(name='hmc_sdc_ecc',
     >>> allcorr.inputs.inputnode.in_bvec = 'diffusion.bvec'
     >>> allcorr.inputs.inputnode.bmap_mag = 'magnitude.nii'
     >>> allcorr.inputs.inputnode.bmap_pha = 'phase.nii'
+    >>> allcorr.inputs.inputnode.epi_param = 'epi_param.txt'
     >>> allcorr.run() # doctest: +SKIP
 
     """
-    inputnode = pe.Node(niu.IdentityInterface(fields=['in_file', 'in_bvec',
-                        'in_bval', 'bmap_pha', 'bmap_mag']), name='inputnode')
-
-    outputnode = pe.Node(niu.IdentityInterface(fields=['out_file', 'out_mask',
-                         'out_bvec']), name='outputnode')
-    avg_b0_0 = pe.Node(niu.Function(input_names=['in_dwi', 'in_bval'],
-                       output_names=['out_file'], function=b0_average),
-                       name='b0_avg_pre')
-    avg_b0_1 = pe.Node(niu.Function(input_names=['in_dwi', 'in_bval'],
-                       output_names=['out_file'], function=b0_average),
-                       name='b0_avg_post')
+    inputnode = pe.Node(niu.IdentityInterface(
+        fields=['in_file', 'in_bvec', 'in_bval', 'bmap_pha', 'bmap_mag',
+                'epi_param']), name='inputnode')
+
+    outputnode = pe.Node(niu.IdentityInterface(
+        fields=['out_file', 'out_mask', 'out_bvec']), name='outputnode')
+
+    list_b0 = pe.Node(niu.Function(
+        input_names=['in_bval'], output_names=['out_idx'],
+        function=b0_indices), name='B0indices')
+
+    avg_b0_0 = pe.Node(niu.Function(
+        input_names=['in_file', 'index'], output_names=['out_file'],
+        function=time_avg), name='b0_avg_pre')
+    avg_b0_1 = pe.Node(niu.Function(
+        input_names=['in_file', 'index'], output_names=['out_file'],
+        function=time_avg), name='b0_avg_post')
+
     bet_dwi0 = pe.Node(fsl.BET(frac=0.3, mask=True, robust=True),
                        name='bet_dwi_pre')
     bet_dwi1 = pe.Node(fsl.BET(frac=0.3, mask=True, robust=True),
                        name='bet_dwi_post')
 
     hmc = hmc_pipeline()
-    sdc = sdc_fmb(fugue_params=fugue_params, bmap_params=bmap_params,
-                  epi_params=epi_params)
+    sdc = sdc_fmb(fugue_params=fugue_params)
     ecc = ecc_pipeline()
     unwarp = apply_all_corrections()
 
@@ -70,21 +72,25 @@ def all_fmb_pipeline(name='hmc_sdc_ecc',
         (inputnode, hmc,        [('in_file', 'inputnode.in_file'),
                                  ('in_bvec', 'inputnode.in_bvec'),
                                  ('in_bval', 'inputnode.in_bval')]),
-        (inputnode, avg_b0_0,   [('in_file', 'in_dwi'),
-                                 ('in_bval', 'in_bval')]),
+        (inputnode, list_b0,    [('in_bval', 'in_bval')]),
+        (inputnode, avg_b0_0,   [('in_file', 'in_file')]),
+        (list_b0,   avg_b0_0,   [('out_idx', 'index')]),
         (avg_b0_0,  bet_dwi0,   [('out_file', 'in_file')]),
         (bet_dwi0,  hmc,        [('mask_file', 'inputnode.in_mask')]),
-        (hmc,       sdc,        [('outputnode.out_file', 'inputnode.in_file')]),
+        (hmc,       sdc,        [
+         ('outputnode.out_file', 'inputnode.in_file')]),
         (bet_dwi0,  sdc,        [('mask_file', 'inputnode.in_mask')]),
-        (inputnode, sdc,        [('in_bval', 'inputnode.in_bval'),
-                                 ('bmap_pha', 'inputnode.bmap_pha'),
-                                 ('bmap_mag', 'inputnode.bmap_mag')]),
-        (hmc,       ecc,        [('outputnode.out_xfms', 'inputnode.in_xfms')]),
+        (inputnode, sdc,        [('bmap_pha', 'inputnode.bmap_pha'),
+                                 ('bmap_mag', 'inputnode.bmap_mag'),
+                                 ('epi_param', 'inputnode.settings')]),
+        (list_b0,   sdc,        [('out_idx', 'inputnode.in_ref')]),
+        (hmc,       ecc,        [
+         ('outputnode.out_xfms', 'inputnode.in_xfms')]),
         (inputnode, ecc,        [('in_file', 'inputnode.in_file'),
                                  ('in_bval', 'inputnode.in_bval')]),
         (bet_dwi0,  ecc,        [('mask_file', 'inputnode.in_mask')]),
-        (ecc,       avg_b0_1,   [('outputnode.out_file', 'in_dwi')]),
-        (inputnode, avg_b0_1,   [('in_bval', 'in_bval')]),
+        (ecc,       avg_b0_1,   [('outputnode.out_file', 'in_file')]),
+        (list_b0,   avg_b0_1,   [('out_idx', 'index')]),
         (avg_b0_1,  bet_dwi1,   [('out_file', 'in_file')]),
         (inputnode, unwarp,     [('in_file', 'inputnode.in_dwi')]),
         (hmc,       unwarp,     [('outputnode.out_xfms', 'inputnode.in_hmc')]),
@@ -127,18 +133,19 @@ def all_peb_pipeline(name='hmc_sdc_ecc',
     >>> allcorr.run() # doctest: +SKIP
 
     """
-    inputnode = pe.Node(niu.IdentityInterface(fields=['in_file', 'in_bvec',
-                        'in_bval', 'alt_file']), name='inputnode')
-
-    outputnode = pe.Node(niu.IdentityInterface(fields=['out_file', 'out_mask',
-                         'out_bvec']), name='outputnode')
-
-    avg_b0_0 = pe.Node(niu.Function(input_names=['in_dwi', 'in_bval'],
-                       output_names=['out_file'], function=b0_average),
-                       name='b0_avg_pre')
-    avg_b0_1 = pe.Node(niu.Function(input_names=['in_dwi', 'in_bval'],
-                       output_names=['out_file'], function=b0_average),
-                       name='b0_avg_post')
+    inputnode = pe.Node(niu.IdentityInterface(
+        fields=['in_file', 'in_bvec', 'in_bval', 'alt_file']),
+        name='inputnode')
+
+    outputnode = pe.Node(niu.IdentityInterface(
+        fields=['out_file', 'out_mask', 'out_bvec']), name='outputnode')
+
+    avg_b0_0 = pe.Node(niu.Function(
+        input_names=['in_dwi', 'in_bval'], output_names=['out_file'],
+        function=b0_average), name='b0_avg_pre')
+    avg_b0_1 = pe.Node(niu.Function(
+        input_names=['in_dwi', 'in_bval'], output_names=['out_file'],
+        function=b0_average), name='b0_avg_post')
     bet_dwi0 = pe.Node(fsl.BET(frac=0.3, mask=True, robust=True),
                        name='bet_dwi_pre')
     bet_dwi1 = pe.Node(fsl.BET(frac=0.3, mask=True, robust=True),
@@ -159,14 +166,16 @@ def all_peb_pipeline(name='hmc_sdc_ecc',
                                  ('in_bval', 'in_bval')]),
         (avg_b0_0,  bet_dwi0,   [('out_file', 'in_file')]),
         (bet_dwi0,  hmc,        [('mask_file', 'inputnode.in_mask')]),
-        (hmc,       sdc,        [('outputnode.out_file', 'inputnode.in_file')]),
+        (hmc,       sdc,        [
+         ('outputnode.out_file', 'inputnode.in_file')]),
         (bet_dwi0,  sdc,        [('mask_file', 'inputnode.in_mask')]),
         (inputnode, sdc,        [('in_bval', 'inputnode.in_bval'),
                                  ('alt_file', 'inputnode.alt_file')]),
         (inputnode, ecc,        [('in_file', 'inputnode.in_file'),
                                  ('in_bval', 'inputnode.in_bval')]),
         (bet_dwi0,  ecc,        [('mask_file', 'inputnode.in_mask')]),
-        (hmc,       ecc,        [('outputnode.out_xfms', 'inputnode.in_xfms')]),
+        (hmc,       ecc,        [
+         ('outputnode.out_xfms', 'inputnode.in_xfms')]),
         (ecc,       avg_b0_1,   [('outputnode.out_file', 'in_dwi')]),
         (inputnode, avg_b0_1,   [('in_bval', 'in_bval')]),
         (avg_b0_1,  bet_dwi1,   [('out_file', 'in_file')]),
@@ -213,11 +222,12 @@ def all_fsl_pipeline(name='fsl_all_correct',
 
     """
 
-    inputnode = pe.Node(niu.IdentityInterface(fields=['in_file', 'in_bvec',
-                        'in_bval', 'alt_file']), name='inputnode')
+    inputnode = pe.Node(niu.IdentityInterface(
+        fields=['in_file', 'in_bvec', 'in_bval', 'alt_file']),
+        name='inputnode')
 
-    outputnode = pe.Node(niu.IdentityInterface(fields=['out_file', 'out_mask',
-                         'out_bvec']), name='outputnode')
+    outputnode = pe.Node(niu.IdentityInterface(
+        fields=['out_file', 'out_mask', 'out_bvec']), name='outputnode')
 
     def _gen_index(in_file):
         import numpy as np
@@ -228,20 +238,20 @@ def _gen_index(in_file):
         np.savetxt(out_file, np.ones((vols,)).T)
         return out_file
 
-    avg_b0_0 = pe.Node(niu.Function(input_names=['in_dwi', 'in_bval'],
-                       output_names=['out_file'], function=b0_average),
-                       name='b0_avg_pre')
+    avg_b0_0 = pe.Node(niu.Function(
+        input_names=['in_dwi', 'in_bval'], output_names=['out_file'],
+        function=b0_average), name='b0_avg_pre')
     bet_dwi0 = pe.Node(fsl.BET(frac=0.3, mask=True, robust=True),
                        name='bet_dwi_pre')
 
     sdc = sdc_peb(epi_params=epi_params, altepi_params=altepi_params)
     ecc = pe.Node(fsl.Eddy(method='jac'), name='fsl_eddy')
-    rot_bvec = pe.Node(niu.Function(input_names=['in_bvec', 'eddy_params'],
-                       output_names=['out_file'], function=eddy_rotate_bvecs),
-                       name='Rotate_Bvec')
-    avg_b0_1 = pe.Node(niu.Function(input_names=['in_dwi', 'in_bval'],
-                       output_names=['out_file'], function=b0_average),
-                       name='b0_avg_post')
+    rot_bvec = pe.Node(niu.Function(
+        input_names=['in_bvec', 'eddy_params'], output_names=['out_file'],
+        function=eddy_rotate_bvecs), name='Rotate_Bvec')
+    avg_b0_1 = pe.Node(niu.Function(
+        input_names=['in_dwi', 'in_bval'], output_names=['out_file'],
+        function=b0_average), name='b0_avg_post')
     bet_dwi1 = pe.Node(fsl.BET(frac=0.3, mask=True, robust=True),
                        name='bet_dwi_post')
 
@@ -255,7 +265,8 @@ def _gen_index(in_file):
                                    ('alt_file', 'inputnode.alt_file'),
                                    ('in_bval', 'inputnode.in_bval')]),
         (sdc,         ecc,        [('topup.out_enc_file', 'in_acqp'),
-                                   ('topup.out_fieldcoef', 'in_topup_fieldcoef'),
+                                   ('topup.out_fieldcoef',
+                                    'in_topup_fieldcoef'),
                                    ('topup.out_movpar', 'in_topup_movpar')]),
         (bet_dwi0,    ecc,        [('mask_file', 'in_mask')]),
         (inputnode,   ecc,        [('in_file', 'in_file'),
@@ -345,22 +356,22 @@ def hmc_pipeline(name='motion_correct'):
                   # cost='mutualinfo', cost_func='mutualinfo', bins=64,
                   schedule=get_flirt_schedule('hmc'))
 
-    inputnode = pe.Node(niu.IdentityInterface(fields=['in_file', 'ref_num',
-                        'in_bvec', 'in_bval', 'in_mask']), name='inputnode')
-    split = pe.Node(niu.Function(function=hmc_split,
-                    input_names=['in_file', 'in_bval', 'ref_num'],
-                    output_names=['out_ref', 'out_mov', 'out_bval', 'volid']),
-                    name='SplitDWI')
+    inputnode = pe.Node(niu.IdentityInterface(
+        fields=['in_file', 'ref_num', 'in_bvec', 'in_bval', 'in_mask']),
+        name='inputnode')
+    split = pe.Node(niu.Function(
+        output_names=['out_ref', 'out_mov', 'out_bval', 'volid'],
+        input_names=['in_file', 'in_bval', 'ref_num'], function=hmc_split),
+        name='SplitDWI')
     flirt = dwi_flirt(flirt_param=params)
     insmat = pe.Node(niu.Function(input_names=['inlist', 'volid'],
-                     output_names=['out'], function=insert_mat),
+                                  output_names=['out'], function=insert_mat),
                      name='InsertRefmat')
-    rot_bvec = pe.Node(niu.Function(input_names=['in_bvec', 'in_matrix'],
-                       output_names=['out_file'], function=rotate_bvecs),
-                       name='Rotate_Bvec')
-    outputnode = pe.Node(niu.IdentityInterface(fields=['out_file',
-                         'out_bvec', 'out_xfms']),
-                         name='outputnode')
+    rot_bvec = pe.Node(niu.Function(
+        function=rotate_bvecs, input_names=['in_bvec', 'in_matrix'],
+        output_names=['out_file']), name='Rotate_Bvec')
+    outputnode = pe.Node(niu.IdentityInterface(
+        fields=['out_file', 'out_bvec', 'out_xfms']), name='outputnode')
 
     wf = pe.Workflow(name=name)
     wf.connect([
@@ -446,14 +457,14 @@ def ecc_pipeline(name='eddy_correct'):
                   schedule=get_flirt_schedule('ecc'))
     # cost='normmi', cost_func='normmi', bins=64,
 
-    inputnode = pe.Node(niu.IdentityInterface(fields=['in_file', 'in_bval',
-                        'in_mask', 'in_xfms']), name='inputnode')
-    avg_b0 = pe.Node(niu.Function(input_names=['in_dwi', 'in_bval'],
-                     output_names=['out_file'], function=b0_average),
-                     name='b0_avg')
-    pick_dws = pe.Node(niu.Function(input_names=['in_dwi', 'in_bval', 'b'],
-                       output_names=['out_file'], function=extract_bval),
-                       name='ExtractDWI')
+    inputnode = pe.Node(niu.IdentityInterface(
+        fields=['in_file', 'in_bval', 'in_mask', 'in_xfms']), name='inputnode')
+    avg_b0 = pe.Node(niu.Function(
+        input_names=['in_dwi', 'in_bval'], output_names=['out_file'],
+        function=b0_average), name='b0_avg')
+    pick_dws = pe.Node(niu.Function(
+        input_names=['in_dwi', 'in_bval', 'b'], output_names=['out_file'],
+        function=extract_bval), name='ExtractDWI')
     pick_dws.inputs.b = 'diff'
 
     flirt = dwi_flirt(flirt_param=params, excl_nodiff=True)
@@ -464,14 +475,15 @@ def ecc_pipeline(name='eddy_correct'):
                        name='RemoveNegative')
 
     split = pe.Node(fsl.Split(dimension='t'), name='SplitDWIs')
-    get_mat = pe.Node(niu.Function(input_names=['in_bval', 'in_xfms'],
-                      output_names=['out_files'], function=recompose_xfm),
-                      name='GatherMatrices')
-    merge = pe.Node(niu.Function(input_names=['in_dwi', 'in_bval', 'in_corrected'],
-                    output_names=['out_file'], function=recompose_dwi), name='MergeDWIs')
+    get_mat = pe.Node(niu.Function(
+        input_names=['in_bval', 'in_xfms'], output_names=['out_files'],
+        function=recompose_xfm), name='GatherMatrices')
+    merge = pe.Node(niu.Function(
+        input_names=['in_dwi', 'in_bval', 'in_corrected'],
+        output_names=['out_file'], function=recompose_dwi), name='MergeDWIs')
 
-    outputnode = pe.Node(niu.IdentityInterface(fields=['out_file', 'out_xfms']),
-                         name='outputnode')
+    outputnode = pe.Node(niu.IdentityInterface(
+        fields=['out_file', 'out_xfms']), name='outputnode')
 
     wf = pe.Workflow(name=name)
     wf.connect([
@@ -489,7 +501,7 @@ def ecc_pipeline(name='eddy_correct'):
         (pick_dws,   flirt,      [('out_file', 'inputnode.in_file')]),
         (flirt,      get_mat,    [('outputnode.out_xfms', 'in_xfms')]),
         (flirt,      mult,       [(('outputnode.out_xfms', _xfm_jacobian),
-                                  'operand_value')]),
+                                   'operand_value')]),
         (flirt,      split,      [('outputnode.out_file', 'in_file')]),
         (split,      mult,       [('out_files', 'in_file')]),
         (mult,       thres,      [('out_file', 'in_file')]),
@@ -500,17 +512,13 @@ def ecc_pipeline(name='eddy_correct'):
     return wf
 
 
-def sdc_fmb(name='fmb_correction',
-            fugue_params=dict(smooth3d=2.0),
-            bmap_params=dict(delta_te=2.46e-3),
-            epi_params=dict(echospacing=0.77e-3,
-                            acc_factor=3,
-                            enc_dir='y-')):
+def sdc_fmb(name='fmb_correction', interp='Linear',
+            fugue_params=dict(smooth3d=2.0)):
     """
     SDC stands for susceptibility distortion correction. FMB stands for
     fieldmap-based.
 
-    The fieldmap based method (FMB) implements SDC by using a mapping of the
+    The fieldmap based (FMB) method implements SDC by using a mapping of the
     B0 field as proposed by [Jezzard95]_. This workflow uses the implementation
     of FSL (`FUGUE <http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FUGUE>`_). Phase
     unwrapping is performed using `PRELUDE
@@ -519,16 +527,19 @@ def sdc_fmb(name='fmb_correction',
     script in FSL `fsl_prepare_fieldmap
     <http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FUGUE/Guide#SIEMENS_data>`_.
 
+
+
     Example
     -------
 
     >>> from nipype.workflows.dmri.fsl.artifacts import sdc_fmb
     >>> fmb = sdc_fmb()
     >>> fmb.inputs.inputnode.in_file = 'diffusion.nii'
-    >>> fmb.inputs.inputnode.in_bval = 'diffusion.bval'
+    >>> fmb.inputs.inputnode.in_ref = range(0, 30, 6)
     >>> fmb.inputs.inputnode.in_mask = 'mask.nii'
     >>> fmb.inputs.inputnode.bmap_mag = 'magnitude.nii'
     >>> fmb.inputs.inputnode.bmap_pha = 'phase.nii'
+    >>> fmb.inputs.inputnode.settings = 'epi_param.txt'
     >>> fmb.run() # doctest: +SKIP
 
     .. warning:: Only SIEMENS format fieldmaps are supported.
@@ -545,85 +556,118 @@ def sdc_fmb(name='fmb_correction',
         MRM 49(1):193-197, 2003, doi: 10.1002/mrm.10354.
 
     """
-    inputnode = pe.Node(niu.IdentityInterface(fields=['in_file', 'in_bval',
-                        'in_mask', 'bmap_pha', 'bmap_mag']),
-                        name='inputnode')
-    outputnode = pe.Node(niu.IdentityInterface(fields=['out_file', 'out_vsm',
-                         'out_warp']),
-                         name='outputnode')
 
-    delta_te = epi_params['echospacing'] / (1.0 * epi_params['acc_factor'])
+    epi_defaults = {'delta_te': 2.46e-3, 'echospacing': 0.77e-3,
+                    'acc_factor': 2, 'enc_dir': u'AP'}
+
+    inputnode = pe.Node(niu.IdentityInterface(
+        fields=['in_file', 'in_ref', 'in_mask', 'bmap_pha', 'bmap_mag',
+                'settings']), name='inputnode')
+
+    outputnode = pe.Node(niu.IdentityInterface(
+        fields=['out_file', 'out_vsm', 'out_warp']), name='outputnode')
+
+    r_params = pe.Node(JSONFileGrabber(defaults=epi_defaults),
+                       name='SettingsGrabber')
+    eff_echo = pe.Node(niu.Function(function=_eff_t_echo,
+                                    input_names=['echospacing', 'acc_factor'],
+                                    output_names=['eff_echo']), name='EffEcho')
 
     firstmag = pe.Node(fsl.ExtractROI(t_min=0, t_size=1), name='GetFirst')
     n4 = pe.Node(ants.N4BiasFieldCorrection(dimension=3), name='Bias')
     bet = pe.Node(fsl.BET(frac=0.4, mask=True), name='BrainExtraction')
-    dilate = pe.Node(fsl.maths.MathsCommand(nan2zeros=True,
-                     args='-kernel sphere 5 -dilM'), name='MskDilate')
-    pha2rads = pe.Node(niu.Function(input_names=['in_file'], output_names=['out_file'],
-                       function=siemens2rads), name='PreparePhase')
+    dilate = pe.Node(fsl.maths.MathsCommand(
+        nan2zeros=True, args='-kernel sphere 5 -dilM'), name='MskDilate')
+    pha2rads = pe.Node(niu.Function(
+        input_names=['in_file'], output_names=['out_file'],
+        function=siemens2rads), name='PreparePhase')
     prelude = pe.Node(fsl.PRELUDE(process3d=True), name='PhaseUnwrap')
-    rad2rsec = pe.Node(niu.Function(input_names=['in_file', 'delta_te'],
-                       output_names=['out_file'], function=rads2radsec), name='ToRadSec')
-    rad2rsec.inputs.delta_te = bmap_params['delta_te']
-
-    avg_b0 = pe.Node(niu.Function(input_names=['in_dwi', 'in_bval'],
-                     output_names=['out_file'], function=b0_average), name='b0_avg')
-
-    flirt = pe.Node(fsl.FLIRT(interp='spline', cost='normmi', cost_func='normmi',
-                    dof=6, bins=64, save_log=True, padding_size=10,
-                    searchr_x=[-4, 4], searchr_y=[-4, 4], searchr_z=[-4, 4],
-                    fine_search=1, coarse_search=10),
-                    name='BmapMag2B0')
-    applyxfm = pe.Node(fsl.ApplyXfm(interp='spline', padding_size=10, apply_xfm=True),
-                       name='BmapPha2B0')
+    rad2rsec = pe.Node(niu.Function(
+        input_names=['in_file', 'delta_te'], output_names=['out_file'],
+        function=rads2radsec), name='ToRadSec')
+
+    baseline = pe.Node(niu.Function(
+        input_names=['in_file', 'index'], output_names=['out_file'],
+        function=time_avg), name='Baseline')
+
+    fmm2b0 = pe.Node(ants.Registration(output_warped_image=True),
+                     name="FMm_to_B0")
+    fmm2b0.inputs.transforms = ['Rigid'] * 2
+    fmm2b0.inputs.transform_parameters = [(1.0,)] * 2
+    fmm2b0.inputs.number_of_iterations = [[50], [20]]
+    fmm2b0.inputs.dimension = 3
+    fmm2b0.inputs.metric = ['Mattes', 'Mattes']
+    fmm2b0.inputs.metric_weight = [1.0] * 2
+    fmm2b0.inputs.radius_or_number_of_bins = [64, 64]
+    fmm2b0.inputs.sampling_strategy = ['Regular', 'Random']
+    fmm2b0.inputs.sampling_percentage = [None, 0.2]
+    fmm2b0.inputs.convergence_threshold = [1.e-5, 1.e-8]
+    fmm2b0.inputs.convergence_window_size = [20, 10]
+    fmm2b0.inputs.smoothing_sigmas = [[6.0], [2.0]]
+    fmm2b0.inputs.sigma_units = ['vox'] * 2
+    fmm2b0.inputs.shrink_factors = [[6], [1]]  # ,[1] ]
+    fmm2b0.inputs.use_estimate_learning_rate_once = [True] * 2
+    fmm2b0.inputs.use_histogram_matching = [True] * 2
+    fmm2b0.inputs.initial_moving_transform_com = 0
+    fmm2b0.inputs.collapse_output_transforms = True
+    fmm2b0.inputs.winsorize_upper_quantile = 0.995
+
+    applyxfm = pe.Node(ants.ApplyTransforms(
+        dimension=3, interpolation=interp), name='FMp_to_B0')
 
     pre_fugue = pe.Node(fsl.FUGUE(save_fmap=True), name='PreliminaryFugue')
-    demean = pe.Node(niu.Function(input_names=['in_file', 'in_mask'],
-                     output_names=['out_file'], function=demean_image),
-                     name='DemeanFmap')
+    demean = pe.Node(niu.Function(
+        input_names=['in_file', 'in_mask'], output_names=['out_file'],
+        function=demean_image), name='DemeanFmap')
 
     cleanup = cleanup_edge_pipeline()
 
-    addvol = pe.Node(niu.Function(input_names=['in_file'], output_names=['out_file'],
-                     function=add_empty_vol), name='AddEmptyVol')
+    addvol = pe.Node(niu.Function(
+        input_names=['in_file'], output_names=['out_file'],
+        function=add_empty_vol), name='AddEmptyVol')
 
     vsm = pe.Node(fsl.FUGUE(save_shift=True, **fugue_params),
                   name="ComputeVSM")
-    vsm.inputs.asym_se_time = bmap_params['delta_te']
-    vsm.inputs.dwell_time = delta_te
 
     split = pe.Node(fsl.Split(dimension='t'), name='SplitDWIs')
     merge = pe.Node(fsl.Merge(dimension='t'), name='MergeDWIs')
     unwarp = pe.MapNode(fsl.FUGUE(icorr=True, forward_warping=False),
                         iterfield=['in_file'], name='UnwarpDWIs')
-    unwarp.inputs.unwarp_direction = epi_params['enc_dir']
     thres = pe.MapNode(fsl.Threshold(thresh=0.0), iterfield=['in_file'],
                        name='RemoveNegative')
     vsm2dfm = vsm2warp()
     vsm2dfm.inputs.inputnode.scaling = 1.0
-    vsm2dfm.inputs.inputnode.enc_dir = epi_params['enc_dir']
 
     wf = pe.Workflow(name=name)
     wf.connect([
+        (inputnode,   r_params,   [('settings', 'in_file')]),
+        (r_params,    eff_echo,   [('echospacing', 'echospacing'),
+                                   ('acc_factor', 'acc_factor')]),
         (inputnode,   pha2rads,   [('bmap_pha', 'in_file')]),
         (inputnode,   firstmag,   [('bmap_mag', 'in_file')]),
-        (inputnode,   avg_b0,     [('in_file', 'in_dwi'),
-                                   ('in_bval', 'in_bval')]),
+        (inputnode,   baseline,   [('in_file', 'in_file'),
+                                   ('in_ref', 'index')]),
         (firstmag,    n4,         [('roi_file', 'input_image')]),
         (n4,          bet,        [('output_image', 'in_file')]),
         (bet,         dilate,     [('mask_file', 'in_file')]),
         (pha2rads,    prelude,    [('out_file', 'phase_file')]),
         (n4,          prelude,    [('output_image', 'magnitude_file')]),
         (dilate,      prelude,    [('out_file', 'mask_file')]),
+        (r_params,    rad2rsec,   [('delta_te', 'delta_te')]),
         (prelude,     rad2rsec,   [('unwrapped_phase_file', 'in_file')]),
-        (avg_b0,      flirt,      [('out_file', 'reference')]),
-        (inputnode,   flirt,      [('in_mask', 'ref_weight')]),
-        (n4,          flirt,      [('output_image', 'in_file')]),
-        (dilate,      flirt,      [('out_file', 'in_weight')]),
-        (avg_b0,      applyxfm,   [('out_file', 'reference')]),
-        (rad2rsec,    applyxfm,   [('out_file', 'in_file')]),
-        (flirt,       applyxfm,   [('out_matrix_file', 'in_matrix_file')]),
-        (applyxfm,    pre_fugue,  [('out_file', 'fmap_in_file')]),
+
+        (baseline,    fmm2b0,     [('out_file', 'fixed_image')]),
+        (n4,          fmm2b0,     [('output_image', 'moving_image')]),
+        (inputnode,   fmm2b0,     [('in_mask', 'fixed_image_mask')]),
+        (dilate,      fmm2b0,     [('out_file', 'moving_image_mask')]),
+
+        (baseline,    applyxfm,   [('out_file', 'reference_image')]),
+        (rad2rsec,    applyxfm,   [('out_file', 'input_image')]),
+        (fmm2b0,      applyxfm, [
+            ('forward_transforms', 'transforms'),
+            ('forward_invert_flags', 'invert_transform_flags')]),
+
+        (applyxfm,    pre_fugue,  [('output_image', 'fmap_in_file')]),
         (inputnode,   pre_fugue,  [('in_mask', 'mask_file')]),
         (pre_fugue,   demean,     [('fmap_out_file', 'in_file')]),
         (inputnode,   demean,     [('in_mask', 'in_mask')]),
@@ -632,11 +676,17 @@ def sdc_fmb(name='fmb_correction',
         (cleanup,     addvol,     [('outputnode.out_file', 'in_file')]),
         (inputnode,   vsm,        [('in_mask', 'mask_file')]),
         (addvol,      vsm,        [('out_file', 'fmap_in_file')]),
+        (r_params,    vsm,        [('delta_te', 'asym_se_time')]),
+        (eff_echo,    vsm,        [('eff_echo', 'dwell_time')]),
         (inputnode,   split,      [('in_file', 'in_file')]),
         (split,       unwarp,     [('out_files', 'in_file')]),
         (vsm,         unwarp,     [('shift_out_file', 'shift_in_file')]),
+        (r_params,    unwarp,     [
+            (('enc_dir', _fix_enc_dir), 'unwarp_direction')]),
         (unwarp,      thres,      [('unwarped_file', 'in_file')]),
         (thres,       merge,      [('out_file', 'in_files')]),
+        (r_params,    vsm2dfm,    [
+            (('enc_dir', _fix_enc_dir), 'inputnode.enc_dir')]),
         (merge,       vsm2dfm,    [('merged_file', 'inputnode.in_ref')]),
         (vsm,         vsm2dfm,    [('shift_out_file', 'inputnode.in_vsm')]),
         (merge,       outputnode, [('merged_file', 'out_file')]),
@@ -697,11 +747,11 @@ def sdc_peb(name='peb_correction',
 
     """
 
-    inputnode = pe.Node(niu.IdentityInterface(fields=['in_file', 'in_bval',
-                        'in_mask', 'alt_file', 'ref_num']),
-                        name='inputnode')
-    outputnode = pe.Node(niu.IdentityInterface(fields=['out_file', 'out_vsm',
-                         'out_warp']), name='outputnode')
+    inputnode = pe.Node(niu.IdentityInterface(
+        fields=['in_file', 'in_bval', 'in_mask', 'alt_file', 'ref_num']),
+        name='inputnode')
+    outputnode = pe.Node(niu.IdentityInterface(
+        fields=['out_file', 'out_vsm', 'out_warp']), name='outputnode')
 
     b0_ref = pe.Node(fsl.ExtractROI(t_size=1), name='b0_ref')
     b0_alt = pe.Node(fsl.ExtractROI(t_size=1), name='b0_alt')
@@ -775,17 +825,18 @@ def remove_bias(name='bias_correct'):
     >>> bias.run() # doctest: +SKIP
 
     """
-    inputnode = pe.Node(niu.IdentityInterface(fields=['in_file', 'in_bval',
-                        'in_mask']), name='inputnode')
+    inputnode = pe.Node(niu.IdentityInterface(
+        fields=['in_file', 'in_bval', 'in_mask']), name='inputnode')
 
     outputnode = pe.Node(niu.IdentityInterface(fields=['out_file']),
                          name='outputnode')
 
-    avg_b0 = pe.Node(niu.Function(input_names=['in_dwi', 'in_bval'],
-                     output_names=['out_file'], function=b0_average),
-                     name='b0_avg')
-    n4 = pe.Node(ants.N4BiasFieldCorrection(dimension=3,
-                 save_bias=True, bspline_fitting_distance=600), name='Bias_b0')
+    avg_b0 = pe.Node(niu.Function(
+        input_names=['in_dwi', 'in_bval'], output_names=['out_file'],
+        function=b0_average), name='b0_avg')
+    n4 = pe.Node(ants.N4BiasFieldCorrection(
+        dimension=3, save_bias=True, bspline_fitting_distance=600),
+        name='Bias_b0')
     split = pe.Node(fsl.Split(dimension='t'), name='SplitDWIs')
     mult = pe.MapNode(fsl.MultiImageMaths(op_string='-div %s'),
                       iterfield=['in_file'], name='RemoveBiasOfDWIs')
@@ -809,6 +860,24 @@ def remove_bias(name='bias_correct'):
     return wf
 
 
+def _eff_t_echo(echospacing, acc_factor):
+    eff_echo = echospacing / (1.0 * acc_factor)
+    return eff_echo
+
+
+def _fix_enc_dir(enc_dir):
+    enc_dir = enc_dir.lower()
+    if enc_dir == 'lr':
+        return 'x-'
+    if enc_dir == 'rl':
+        return 'x'
+    if enc_dir == 'ap':
+        return 'y-'
+    if enc_dir == 'pa':
+        return 'y'
+    return enc_dir
+
+
 def _checkrnum(ref_num):
     from nipype.interfaces.base import isdefined
     if (ref_num is None) or not isdefined(ref_num):
diff --git a/nipype/workflows/dmri/fsl/utils.py b/nipype/workflows/dmri/fsl/utils.py
--- a/nipype/workflows/dmri/fsl/utils.py
+++ b/nipype/workflows/dmri/fsl/utils.py
@@ -381,6 +381,51 @@ def recompose_xfm(in_bval, in_xfms):
     return out_files
 
 
+def time_avg(in_file, index=[0], out_file=None):
+    """
+    Average the input time-series, selecting the indices given in index
+
+    .. warning:: time steps should be already registered (corrected for
+      head motion artifacts).
+
+    """
+    import numpy as np
+    import nibabel as nb
+    import os.path as op
+
+    if out_file is None:
+        fname, ext = op.splitext(op.basename(in_file))
+        if ext == ".gz":
+            fname, ext2 = op.splitext(fname)
+            ext = ext2 + ext
+        out_file = op.abspath("%s_baseline%s" % (fname, ext))
+
+    index = np.atleast_1d(index).tolist()
+
+    imgs = np.array(nb.four_to_three(nb.load(in_file)))[index]
+    if len(index) == 1:
+        data = imgs[0].get_data().astype(np.float32)
+    else:
+        data = np.average(np.array([im.get_data().astype(np.float32) for im in imgs]),
+                         axis=0)
+
+    hdr = imgs[0].get_header().copy()
+    hdr.set_data_shape(data.shape)
+    hdr.set_xyzt_units('mm')
+    hdr.set_data_dtype(np.float32)
+    nb.Nifti1Image(data, imgs[0].get_affine(), hdr).to_filename(out_file)
+    return out_file
+
+
+def b0_indices(in_bval, max_b=10.0):
+    """
+    Extract the indices of slices in a b-values file with a low b value
+    """
+    import numpy as np
+    bval = np.loadtxt(in_bval)
+    return np.argwhere(bval <= max_b).flatten().tolist()
+
+
 def b0_average(in_dwi, in_bval, max_b=10.0, out_file=None):
     """
     A function that averages the *b0* volumes from a DWI dataset.
@@ -403,9 +448,9 @@ def b0_average(in_dwi, in_bval, max_b=10.0, out_file=None):
         out_file = op.abspath("%s_avg_b0%s" % (fname, ext))
 
     imgs = np.array(nb.four_to_three(nb.load(in_dwi)))
-    bval = np.loadtxt(in_bval)
+    index = b0_indices(in_bval, max_b=max_b)
     b0s = [im.get_data().astype(np.float32)
-           for im in imgs[np.where(bval <= max_b)]]
+           for im in imgs[index]]
     b0 = np.average(np.array(b0s), axis=0)
 
     hdr = imgs[0].get_header().copy()


Test patch:
diff --git a/nipype/testing/data/epi_param.txt b/nipype/testing/data/epi_param.txt
new file mode 100644
--- /dev/null
+++ b/nipype/testing/data/epi_param.txt
@@ -0,0 +1,10 @@
+{
+    "enc_dir": "y-",
+    "echospacing": 7.800117313764398e-4,
+    "delta_te": 2.46e-3,
+    "epi_factor": 128,
+    "epi_lines": 57,
+    "epi_acc": 2,
+    "field_strength": 3.0,
+    "field_axis": "z"
+}